From c0dcf7c2bc72b370bc1d85f16c4231433bf71c7c Mon Sep 17 00:00:00 2001 From: Lou Quillio Date: Sun, 9 Jul 2017 18:33:42 -0700 Subject: [PATCH 1/4] Port Draco bitstream spec to Markdown. This represents the grunt-work of porting the gDocs document to plaintext. There are decisions to make and polish to be applied. --- docs/Gemfile.lock | 199 ++ docs/_config.yml | 34 + docs/_layouts/spec.html | 29 + docs/_site/DracoLogo.jpeg | Bin 0 -> 20683 bytes docs/_site/artwork/draco3d-horiz-320x79.png | Bin 0 -> 8622 bytes docs/_site/artwork/draco3d-horiz-640x158.png | Bin 0 -> 19412 bytes docs/_site/artwork/draco3d-horiz.ai | 348 +++ docs/_site/artwork/draco3d-horiz.svg | 323 +++ docs/_site/artwork/draco3d-mark-180x180.png | Bin 0 -> 13055 bytes docs/_site/artwork/draco3d-mark-360x360.png | Bin 0 -> 29971 bytes docs/_site/artwork/draco3d-mark.ai | 364 ++++ docs/_site/artwork/draco3d-mark.svg | 306 +++ docs/_site/artwork/draco3d-vert-180x137.png | Bin 0 -> 9189 bytes docs/_site/artwork/draco3d-vert-360x274.png | Bin 0 -> 19836 bytes docs/_site/artwork/draco3d-vert-452x344.png | Bin 0 -> 25782 bytes docs/_site/artwork/draco3d-vert.ai | 424 ++++ docs/_site/artwork/draco3d-vert.svg | 374 ++++ docs/_site/assets/css/pygments/README.md | 23 + docs/_site/assets/css/pygments/UNLICENSE.txt | 24 + docs/_site/assets/css/pygments/autumn.css | 58 + docs/_site/assets/css/pygments/borland.css | 46 + docs/_site/assets/css/pygments/bw.css | 34 + docs/_site/assets/css/pygments/colorful.css | 61 + docs/_site/assets/css/pygments/default.css | 61 + docs/_site/assets/css/pygments/emacs.css | 61 + docs/_site/assets/css/pygments/friendly.css | 61 + docs/_site/assets/css/pygments/fruity.css | 70 + docs/_site/assets/css/pygments/github.css | 61 + docs/_site/assets/css/pygments/index.html | 27 + docs/_site/assets/css/pygments/manni.css | 61 + docs/_site/assets/css/pygments/monokai.css | 66 + docs/_site/assets/css/pygments/murphy.css | 61 + docs/_site/assets/css/pygments/native.css | 70 + docs/_site/assets/css/pygments/pastie.css | 60 + docs/_site/assets/css/pygments/perldoc.css | 58 + docs/_site/assets/css/pygments/tango.css | 69 + docs/_site/assets/css/pygments/trac.css | 59 + docs/_site/assets/css/pygments/vim.css | 70 + docs/_site/assets/css/pygments/vs.css | 33 + docs/_site/assets/css/pygments/zenburn.css | 136 ++ docs/_site/assets/css/spec-style.css | 1 + docs/_site/assets/favicon.ico | Bin 0 -> 1406 bytes docs/_site/assets/js/ASCIIMathML.js | 1127 ++++++++++ ...igation-For-Your-Long-Document-autoTOC.zip | Bin 0 -> 5047 bytes docs/_site/assets/js/jquery.autotoc.js | 58 + docs/_site/spec/00.00.00.title.html | 2 + docs/_site/spec/00.00.00.title.md | 3 + docs/_site/spec/00.00.01.version.html | 3 + docs/_site/spec/00.00.01.version.md | 3 + docs/_site/spec/00.00.02.authors.html | 4 + docs/_site/spec/00.00.02.authors.md | 4 + docs/_site/spec/00.00.03.last.modified.html | 2 + docs/_site/spec/00.00.03.last.modified.md | 2 + docs/_site/spec/00.00.04.abstract.html | 5 + docs/_site/spec/00.00.04.abstract.md | 6 + docs/_site/spec/00.00.05.toc.html | 3 + docs/_site/spec/00.00.05.toc.md | 5 + docs/_site/spec/01.00.00.scope.html | 5 + docs/_site/spec/01.00.00.scope.md | 5 + docs/_site/spec/02.00.00.terms.html | 19 + docs/_site/spec/02.00.00.terms.md | 8 + docs/_site/spec/03.00.00.symbols.html | 30 + docs/_site/spec/03.00.00.symbols.md | 18 + docs/_site/spec/04.00.00.conventions.html | 42 + docs/_site/spec/04.00.00.conventions.md | 26 + docs/_site/spec/draco.decoder.html | 43 + docs/_site/spec/draco.decoder.md | 45 + docs/_site/spec/edgebreaker.decoder.html | 1556 +++++++++++++ docs/_site/spec/edgebreaker.decoder.md | 1674 ++++++++++++++ docs/_site/spec/index.html | 1927 +++++++++++++++++ docs/_site/spec/mesh.decoder.html | 11 + docs/_site/spec/mesh.decoder.md | 11 + docs/assets/css/pygments/README.md | 23 + docs/assets/css/pygments/UNLICENSE.txt | 24 + docs/assets/css/pygments/autumn.css | 58 + docs/assets/css/pygments/borland.css | 46 + docs/assets/css/pygments/bw.css | 34 + docs/assets/css/pygments/colorful.css | 61 + docs/assets/css/pygments/default.css | 61 + docs/assets/css/pygments/emacs.css | 61 + docs/assets/css/pygments/friendly.css | 61 + docs/assets/css/pygments/fruity.css | 70 + docs/assets/css/pygments/github.css | 61 + docs/assets/css/pygments/manni.css | 61 + docs/assets/css/pygments/monokai.css | 66 + docs/assets/css/pygments/murphy.css | 61 + docs/assets/css/pygments/native.css | 70 + docs/assets/css/pygments/pastie.css | 60 + docs/assets/css/pygments/perldoc.css | 58 + docs/assets/css/pygments/tango.css | 69 + docs/assets/css/pygments/trac.css | 59 + docs/assets/css/pygments/vim.css | 70 + docs/assets/css/pygments/vs.css | 33 + docs/assets/css/pygments/zenburn.css | 136 ++ docs/assets/css/spec-style.sass | 99 + docs/assets/favicon.ico | Bin 0 -> 1406 bytes docs/assets/js/ASCIIMathML.js | 1127 ++++++++++ ...igation-For-Your-Long-Document-autoTOC.zip | Bin 0 -> 5047 bytes docs/assets/js/jquery.autotoc.js | 58 + docs/spec/00.00.00.title.md | 3 + docs/spec/00.00.01.version.md | 3 + docs/spec/00.00.02.authors.md | 4 + docs/spec/00.00.03.last.modified.md | 2 + docs/spec/00.00.04.abstract.md | 6 + docs/spec/00.00.05.toc.md | 5 + docs/spec/01.00.00.scope.md | 5 + docs/spec/02.00.00.terms.md | 8 + docs/spec/03.00.00.symbols.md | 18 + docs/spec/04.00.00.conventions.md | 26 + docs/spec/draco.decoder.md | 45 + docs/spec/edgebreaker.decoder.md | 1674 ++++++++++++++ docs/spec/index.md | 32 + docs/spec/mesh.decoder.md | 11 + 113 files changed, 14808 insertions(+) create mode 100644 docs/Gemfile.lock create mode 100644 docs/_config.yml create mode 100644 docs/_layouts/spec.html create mode 100644 docs/_site/DracoLogo.jpeg create mode 100644 docs/_site/artwork/draco3d-horiz-320x79.png create mode 100644 docs/_site/artwork/draco3d-horiz-640x158.png create mode 100644 docs/_site/artwork/draco3d-horiz.ai create mode 100644 docs/_site/artwork/draco3d-horiz.svg create mode 100644 docs/_site/artwork/draco3d-mark-180x180.png create mode 100644 docs/_site/artwork/draco3d-mark-360x360.png create mode 100644 docs/_site/artwork/draco3d-mark.ai create mode 100644 docs/_site/artwork/draco3d-mark.svg create mode 100644 docs/_site/artwork/draco3d-vert-180x137.png create mode 100644 docs/_site/artwork/draco3d-vert-360x274.png create mode 100644 docs/_site/artwork/draco3d-vert-452x344.png create mode 100644 docs/_site/artwork/draco3d-vert.ai create mode 100644 docs/_site/artwork/draco3d-vert.svg create mode 100644 docs/_site/assets/css/pygments/README.md create mode 100644 docs/_site/assets/css/pygments/UNLICENSE.txt create mode 100644 docs/_site/assets/css/pygments/autumn.css create mode 100644 docs/_site/assets/css/pygments/borland.css create mode 100644 docs/_site/assets/css/pygments/bw.css create mode 100644 docs/_site/assets/css/pygments/colorful.css create mode 100644 docs/_site/assets/css/pygments/default.css create mode 100644 docs/_site/assets/css/pygments/emacs.css create mode 100644 docs/_site/assets/css/pygments/friendly.css create mode 100644 docs/_site/assets/css/pygments/fruity.css create mode 100644 docs/_site/assets/css/pygments/github.css create mode 100644 docs/_site/assets/css/pygments/index.html create mode 100644 docs/_site/assets/css/pygments/manni.css create mode 100644 docs/_site/assets/css/pygments/monokai.css create mode 100644 docs/_site/assets/css/pygments/murphy.css create mode 100644 docs/_site/assets/css/pygments/native.css create mode 100644 docs/_site/assets/css/pygments/pastie.css create mode 100644 docs/_site/assets/css/pygments/perldoc.css create mode 100644 docs/_site/assets/css/pygments/tango.css create mode 100644 docs/_site/assets/css/pygments/trac.css create mode 100644 docs/_site/assets/css/pygments/vim.css create mode 100644 docs/_site/assets/css/pygments/vs.css create mode 100644 docs/_site/assets/css/pygments/zenburn.css create mode 100644 docs/_site/assets/css/spec-style.css create mode 100644 docs/_site/assets/favicon.ico create mode 100644 docs/_site/assets/js/ASCIIMathML.js create mode 100644 docs/_site/assets/js/Generating-An-In-page-Navigation-For-Your-Long-Document-autoTOC.zip create mode 100644 docs/_site/assets/js/jquery.autotoc.js create mode 100644 docs/_site/spec/00.00.00.title.html create mode 100644 docs/_site/spec/00.00.00.title.md create mode 100644 docs/_site/spec/00.00.01.version.html create mode 100644 docs/_site/spec/00.00.01.version.md create mode 100644 docs/_site/spec/00.00.02.authors.html create mode 100644 docs/_site/spec/00.00.02.authors.md create mode 100644 docs/_site/spec/00.00.03.last.modified.html create mode 100644 docs/_site/spec/00.00.03.last.modified.md create mode 100644 docs/_site/spec/00.00.04.abstract.html create mode 100644 docs/_site/spec/00.00.04.abstract.md create mode 100644 docs/_site/spec/00.00.05.toc.html create mode 100644 docs/_site/spec/00.00.05.toc.md create mode 100644 docs/_site/spec/01.00.00.scope.html create mode 100644 docs/_site/spec/01.00.00.scope.md create mode 100644 docs/_site/spec/02.00.00.terms.html create mode 100644 docs/_site/spec/02.00.00.terms.md create mode 100644 docs/_site/spec/03.00.00.symbols.html create mode 100644 docs/_site/spec/03.00.00.symbols.md create mode 100644 docs/_site/spec/04.00.00.conventions.html create mode 100644 docs/_site/spec/04.00.00.conventions.md create mode 100644 docs/_site/spec/draco.decoder.html create mode 100644 docs/_site/spec/draco.decoder.md create mode 100644 docs/_site/spec/edgebreaker.decoder.html create mode 100644 docs/_site/spec/edgebreaker.decoder.md create mode 100644 docs/_site/spec/index.html create mode 100644 docs/_site/spec/mesh.decoder.html create mode 100644 docs/_site/spec/mesh.decoder.md create mode 100644 docs/assets/css/pygments/README.md create mode 100644 docs/assets/css/pygments/UNLICENSE.txt create mode 100644 docs/assets/css/pygments/autumn.css create mode 100644 docs/assets/css/pygments/borland.css create mode 100644 docs/assets/css/pygments/bw.css create mode 100644 docs/assets/css/pygments/colorful.css create mode 100644 docs/assets/css/pygments/default.css create mode 100644 docs/assets/css/pygments/emacs.css create mode 100644 docs/assets/css/pygments/friendly.css create mode 100644 docs/assets/css/pygments/fruity.css create mode 100644 docs/assets/css/pygments/github.css create mode 100644 docs/assets/css/pygments/manni.css create mode 100644 docs/assets/css/pygments/monokai.css create mode 100644 docs/assets/css/pygments/murphy.css create mode 100644 docs/assets/css/pygments/native.css create mode 100644 docs/assets/css/pygments/pastie.css create mode 100644 docs/assets/css/pygments/perldoc.css create mode 100644 docs/assets/css/pygments/tango.css create mode 100644 docs/assets/css/pygments/trac.css create mode 100644 docs/assets/css/pygments/vim.css create mode 100644 docs/assets/css/pygments/vs.css create mode 100644 docs/assets/css/pygments/zenburn.css create mode 100644 docs/assets/css/spec-style.sass create mode 100644 docs/assets/favicon.ico create mode 100644 docs/assets/js/ASCIIMathML.js create mode 100644 docs/assets/js/Generating-An-In-page-Navigation-For-Your-Long-Document-autoTOC.zip create mode 100644 docs/assets/js/jquery.autotoc.js create mode 100644 docs/spec/00.00.00.title.md create mode 100644 docs/spec/00.00.01.version.md create mode 100644 docs/spec/00.00.02.authors.md create mode 100644 docs/spec/00.00.03.last.modified.md create mode 100644 docs/spec/00.00.04.abstract.md create mode 100644 docs/spec/00.00.05.toc.md create mode 100644 docs/spec/01.00.00.scope.md create mode 100644 docs/spec/02.00.00.terms.md create mode 100644 docs/spec/03.00.00.symbols.md create mode 100644 docs/spec/04.00.00.conventions.md create mode 100644 docs/spec/draco.decoder.md create mode 100644 docs/spec/edgebreaker.decoder.md create mode 100644 docs/spec/index.md create mode 100644 docs/spec/mesh.decoder.md 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..06dd47f --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,34 @@ +# 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 +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/_site/DracoLogo.jpeg b/docs/_site/DracoLogo.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d41c320d8a40e6b8feae154ec50a3b432e6ca620 GIT binary patch literal 20683 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 S{_hEz|2p6CKYZD~4gLi(4p9;S literal 0 HcmV?d00001 diff --git a/docs/_site/artwork/draco3d-horiz-320x79.png b/docs/_site/artwork/draco3d-horiz-320x79.png new file mode 100644 index 0000000000000000000000000000000000000000..17838c6625f231435d340121088e5533012e764a GIT binary patch literal 8622 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 E00E~}NB{r; literal 0 HcmV?d00001 diff --git a/docs/_site/artwork/draco3d-horiz.ai b/docs/_site/artwork/draco3d-horiz.ai new file mode 100644 index 0000000..381c884 --- /dev/null +++ b/docs/_site/artwork/draco3d-horiz.ai @@ -0,0 +1,348 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[5 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + Adobe Illustrator CC 2015.3 (Macintosh) + 2016-10-31T10:56:20-05:00 + 2016-10-31T10:56:20-05:00 + 2016-10-31T10:56:20-05:00 + + + + 256 + 64 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAQAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q88/Nn88PJ/5bWajU XN7rU687TRrdh6zr0DyMaiKOo+0ev7INDir5I88/85O/mr5pmkS31JtB05j+7s9MJhYD/LuB++Y0 60YD2xV5be6hf30xnvbmW6mPWWZ2kY/7JiTiqppms6vpU4n0y+uLCcbiW2leF6j/ACkKnFXrvkH/ AJyu/M3y3NFDrE48yaWpAeC9NLkL34XSjny95A+Kvrv8tfzW8n/mHpJvtBuf38QH13TpqLcwMezo CaqezKSp8cVZhirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirz 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 V2KuxV2Kv//Z + + + + 1 + False + False + + 10.888902 + 4.355556 + Inches + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + Document + application/pdf + + + DRACO_ID_horiz + + + proof:pdf + uuid:31458fc1-188b-9f40-ac8f-d6f37511f8e0 + uuid:ad63e1da-0fe2-1b46-99cd-97a55da3e11d + Adobe PDF library 15.00 + + + + + + + + + + + + + + + + + + + + + + + + + endstream endobj 3 0 obj <> endobj 7 0 obj <>/Resources<>/Properties<>>>/Thumb 11 0 R/TrimBox[0.0 0.0 784.001 313.6]/Type/Page>> endobj 8 0 obj <>stream +HtWK$ )-J"%mf50 /|{f1`TVkw~E>#_?h֮8W)vi?>8LCvnWm~5los縆ϣ kJi|<WDK󷧙Gz@9N;eӏn=qfê6I~-Da[gQL>ʹϻtߏE~ٚrsDm`酀LXMc[ؾoO\pW ^حFzEa81Vgq*`1Gk1 +7p\e mWZ;߶&0uѯʈw  2Z0+p].ŀ "9Up8?F}sW=wϻoo/O3HC{`` %8!  }Q]P9(D+LUL=TEY騗0)F4}N_4UqMf2[4c4Tm Pφ B&UuurՅ:\ L$>̘Cf- +:ӑ '*O={x@Oߣ2׽Me瞠E΍JgkOw*]CytB 5=}1B)JPawB'5yՍT$9xOk6$k]K>eEρ7Kd<Nب&yx(]j53*7Bˮf?&8xҲilAc(~NЪ Ur."wu }PdRw(MJ +W{6 8jn!Yq hXWriсZFcm0` +E3 2ej$8J\;˪ +nyS%FK +n=JX,O }H.pG~wn5H_Du3E]|rly _BmR<"`%:/rgR$L2QuvkLͦvGѪȫ q4 $ Fc=V K*͓>2I6чU=,S$ .D 6l:$QKZ5]'Y&GFPR2%Fe[N_ CHXl!%YtLcS{߹_,81l‹S="(> A,bDREFtndXtf nc!*T"{{K`t6{4||I"\/ꀎNYzYS{ԥF˾]t<,Yv7 )!&&՜:IzI`ZYQgc]",aa 6k(S )j* AV~ R * }BAᏼE2ҔDb?hV0 \-2CY5ŠML8Y7t3djaJH`wj7+|+@)m‘# 5q#Cˬ#,#bFW%tqM}2oКR^ƭ~+˅ZIM,a_gX[.$`|ci02łafRLZx9jD2.fKBQjEFjb՗|( +On<>0S̖m$=5^x@]/馞X!~ܭ_݉ũujG|ȎDf{8)&εXRd)AT75\x@VK<|Ub>~c{yvwhYHIթ +Pj\r贇B֑qdQI ]cpO1A8?ā*[ +]ڛAE+t6ѿ~#ztͨYPb/b}M XkZ/wmoeoL*AHX|mfBx+0ی0|ٴ;j}CHbDŎ@R!߀9HX7B=+?v5VzufUK^WbdTN@3|!>("&o]-(7˖ߝL1L ~튞v]dpuغ#Q\Tba??),E:zus +60N ZXu^-hxq?d-j/ Y]'U +\H2A5\͂&g\OӿefD +JVP!|ᜄZŎ kƻiqVU>kt8"j厳[ƅ :'P̍1(IXWm퉭t5jsw@6, + +qV'#d۪OՕp7JULEѠlڷẙ5y# @afȨi 3i +1aT{npUF, lJ\,`Pf:FOlEfu(ӻ?]5=* O]V߶ x,|ۺL=RK~V|vosA)ajDc M t[J\fWSӓ.R1t'ifWN[O (m\?1GjFù߼~*DNχ5$ -Qc|ݙ5|7 +4Q<7鏥J +jޯǡLsSݙ,5kImXHLz0ʾ폧{Hڌx0+q===m YǛatbZF@oWxKҙM~ʋ19*⵵xeڰA-XK'h''8'u:`zHF+k=f]!8x|5!(>Vɡ[ԮL?*)_T2;gm/<<)/Κit^|SGI`yۮ\)v[Ra?Lwyfi<xZ zE]˯Pf3jѥf6f9aG[avxxj >NC=dm8ѾHA{!ݟ˟D#QfV"4䣕>t (I+@3"Q]UO] + ]b/]?*km؜{wD q%bXx,1xivXC><5mK_788f8kO'd89md=T*ʰڏW?$⟒^{\VHk.—1pLѓEMsstThan?f*A #p +d:]=%banj̬>9"t(C {6*%R(OPZl956| I[dڀeUq̹T}Y.E"d|eZeO~UQ O.>i=Y Qd*[C A0 `L[@xl˃k$MKzjzZv@jݞk"Nh?tHݟMfh;DWiXՒǃk*8NASTٕfY2U)iSջ(e{\h'Cq9׬uo`Xsv|ߵ㍶ΕSG u;  yEY{u<4!:.*xC_.|bt +\-2SyڸZ[Np@Ur,>n,}[Z}.>5>tE%Xu|6 WFTp*!rry3Y -U4]G =rT=zCh`B!v /6pMڭcXA+3E {*š^{#AoT˛ŝ +J*Ho=&F3~a؏^4L%C@utR$.BYtx஁r4En~V75* "'E`nn٫F^ߛ!s.“<@2Й HR1p*pg|6&Xr-Y~R] l8 y]noyK0TZ3;6T9j(yXx-|_4# ~R^\hqy7k>[xZfy \&[ եbSVStr7_` Y fHG7,f `vǔU=p| ~:ǔwW@#f[]9څ{^ʷ_@ dyWz6|Xr'o +O6~J]${iw-D&I'Xitv"M3mZsQVİ6>d~;rmbgs@yH͕2{IPCs@k{TRF\N${稺G1A?rP!jݪ`U&B/4@3b[a= +*"z%`DQhP j}ijN,u]8U'}`g1+FԼ|!gǙ;*ub\K!pdhA=+턑LnK.ԟvN옸-N bs{XEݥ +YMG'WW!/4KUsKǿ~>OGFB'?S~Ruѿ.22;$5OI.)ʱˁtGB5LGT$],u-+'qGVJjF+s{khkb-aPDR28_>4˖JCqw~3Sl:ř]9[9:+.i-"L]3)zk$Ls9)TpS{`(8*9]!$~n^٠L[p-8C#%r*Fm\oyRAMko"d^(,Mȍ%D6h=B6vwx@_%MoZ[m2)oB\A'F-̖lP1Z;\Cp|/7y&tC(3IJƂ]):w}{TdgPulWI$ +9=}|ATd:e: N"FVM暻l/mIAy֏ԽAuUMD}{;5W#|G}4,7Ӑн滻_ }GJ'E%c }k,y\b>OqsJ'&;uݫ+c +mirdV*~0X߆k0L5l}֛S0-_7>Ы0S#ݻQH .džRv㺨8DQj-,skF ˳g7~!HUC>{זH[B$J>jʂ݉m[~>˧]/ć kkF';`Wäu`O汅RKN@3cɄoxkKl5&`Ρ/`aiso/8a[Bzu~+ #RMi!#G!E I{P,w[x1ڣM(vRsS$%N`ՠ+ ~WϰM a6=oQ=Ɣl#‰K $WG$GGvXi↷8t8W~e#0yWP]|2A:>)s~hGo5β%~ M3u~oǯzIjzŠW@u6 J3q/h T}ˆ v\3}n'^暕>b1 ^0a%*÷f7eva b*a)G7צ|Cfvو.ivX2c6zd沉#:&n}:>>Qoc;26mwSֶ3r>cmA|SAT׽uug-j "YXxjQ)P= 9M]%V 60@OlAv^WBtn }w}4PEo2Fxc#Z;$ȍ5\ {0w*xgj?lj;^h# ~E,vᑬdsgW%K+6rG<x\+|4CFVn`aqĭhaͼZ$&R_.8 Rd Tlh7@Ou9 aF' z6`\IT""3I6FV!00n!ڝ%@r$c3Pו#e&ϥ$o"Ηơe +@oȁ:9Q"\hԟ@or*ltFd_~ͦ R%[V4l4QKףӧc)9=c wqոWhT}Y;C>q0Ƴ$\P;7l@ߒe)<821_F ^c + +:-TwT1ڢ&0={x lK,:U.2H"XVцk? >d`~0 Q)#8Zsɪ g{7j6JTsITٝWʋ ,bz^bNZ^c|j"%᪰*gD^h%(? q,7 himHDX%d_kpAdF_z1={u#WbdxA!WȀz%lw2J>R3w> '5a) *OpkH?`*.,9r$u +] qΣm*2Ag6S|ߏ٭;H'=r b[YآIu~-uF%_W)PXuKO.7FM MO&sU)EsԟU,~Ph-lEx"c鼻Zh U"!x+R}TU5j涸^Tp%Xn#WDmsf~CZ xTl곁_VM(wqR 4vt)i'˸ MV5XpBX\Fҝjƛ{K)UZ|C3J,ո_Е`r6᳕z( KҜj>9,Zh-  4S܅cΨ<:R0bҤ+ncOOZqhG1/;~:ltPa} ukZL^;Dف$S|#Gd +K?."n`S!wbQZp~5!BwE"^ zaë/b5G5ZjZ^k4۫]#?o~7҆0TRBږؾl+Q#85-nkP +w8UG2,,B ~)Q 0%y|vsU*?חWⳭ8ԤLΠ +:|dfVo޼-W+o\n!=ÿTaghT׵vUY{ە4OLDٓNHjTWt[JY)_ S&OIAրBTræxEp/}…`TCvO坟Ix:o }i-ALE<z?CS_ ht@8~jӮa\fAjݍbsvK'eoJa͐$@'떘8b8#mpl^6Qҧ k̙xEH{ >&eiR$PY#JVLDiD#<,>b=B՝05e1WL\F1GQXKFiJDtUb׊+G+|Z]frf}cbpflx{?QN3e\Y#+qҌ'v1Z~<i' h:c9p x +|||$t 5QiUSǫjeS=9ҵ<ט>=xOO?Q~oΞWL*I9asV<!B4uyEy%.zJz=F,?AYvO(UuW`fD-/a + +LK}Dρ$[=@aW 2Γ;?Zo+yI嗍&+qXV4܍`Z 8 Qvޅ ir RwTQ]} [Kάq}e¨P1&KecEQQs me]Cc4\vEٮ,97h>ev;|ۖyV +H[aŁV뮻.I"bN@!g zYjy_,vcO{rd`X %H֍_+wAvE vb>8=0jq$@&L#khn^l/t_~ΝfN^7H"ğ$Ȇ*Fܨ#JUS*:̀XK6 trWQŌ&z1sv1^F :B%-h-EFpeJ +̺Gh28#E14t?c/P/*顚\[HrHz +dVqv@٦x2.**uE^jl̯ +J +?{DQ'L|emgF fc|㗏?>gџb ]u)QxwJš(dW?ۇMZcX3:z Q׬$UA:rZ7ʐ,AE](l>k@1V*Fg"7A{!oӽn/9m7,EqAS1$oY6=( :Y62^T  m],Bz$8-PivI0?사?/& $F?`2:M!EIoGLoS96C+Y۽VEn(hWGo +,sifX$\&`'gv ;XS2uɉUw6^&lx8^]C%u0m ifýʵu]@-', _-yd_s5pyk\t7+ * ^VJċ zʱÌFKmM`pPVW޿|;4waTm1fVs&Us8O9I uVLo OųZ,=4Lٟ~S` endstream endobj 11 0 obj <>stream +8;Z\u;%CJt#Xc0&"`p5K>I55`dcQ0VPOKB&.1_WL*M_/"rCStJ?,)>,+5N%NH'k![15dc4Bc)H/M[VEX.*t50U1u=5GF? +-hpPD' endstream endobj 12 0 obj [/Indexed/DeviceRGB 255 13 0 R] endobj 13 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <> endobj 14 0 obj [/View/Design] endobj 15 0 obj <>>> endobj 10 0 obj <> endobj 9 0 obj <> endobj 16 0 obj <> endobj 17 0 obj <>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 17.0 %%AI8_CreatorVersion: 20.1.0 %%For: (Abby Lindstrom) () %%Title: (DRACO_ID_horiz.svg) %%CreationDate: 10/31/16 10:56 AM %%Canvassize: 16383 %%BoundingBox: 63 75 721 238 %%HiResBoundingBox: 63.7369820929635 75.9780118971212 720.263061523438 237.622017584928 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 13.0 %AI12_BuildNumber: 174 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%RGBProcessColor: 0 0 0 ([Registration]) %AI3_Cropmarks: 0 0 784.0009765625 313.600006103516 %AI3_TemplateBox: 391.5 156.100006103516 391.5 156.100006103516 %AI3_TileBox: 12.00048828125 -133.199996948242 772.00048828125 446.800003051758 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 0 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI17_Begin_Content_if_version_gt:17 1 %AI9_OpenToView: -379 660.600006103516 1 1928 1104 26 0 0 -4 37 0 0 0 1 1 0 1 1 0 1 %AI17_Alternate_Content %AI9_OpenToView: -379 660.600006103516 1 1928 1104 26 0 0 -4 37 0 0 0 1 1 0 1 1 0 1 %AI17_End_Versioned_Content %AI5_OpenViewLayers: 7 %%PageOrigin:86 -240.399993896484 %AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 18 0 obj <>stream +%%BoundingBox: 63 75 721 238 %%HiResBoundingBox: 63.7369820929635 75.9780118971212 720.263061523438 237.622017584928 %AI7_Thumbnail: 128 32 8 %%BeginData: 5102 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FD0AFFA85252FD05F82752A8FD73FF7D27FD0BF82752A8FD6FFF27 %FD10F87DFD6CFF7DFD13F827A8FD69FF7DFD06F827A87D27F8F8F852FD07 %F827FD68FFA8FD05F852A8FFFF52FD04F8527DFD07F827FD67FFFD05F87D %FFA8FFFFF8F8F87D7DFFFFA8FD07F852FD65FF27FD04F87DFF7D27FF52F8 %F8F852FD05FF27FD06F8A8FD0CFFA852527D527D527D7D7DA8FD07FFA852 %527D527D527D527D7DFD0BFF5252527D52A8FD0AFFA87D5252275252FD0B %FF7D522727277D7DFD06FF7DFD04F87DFFFF52A8FF27F8F852FFFFFF5252 %7DA8FD06F827FD0CFFA8FD09F82727A8FD05FF7DFD0BF8A8FD08FF7DFD05 %F827FD09FF52FD08F87DFD07FF7DFD08F827A8FD04FF27F8F8F827FFFFA8 %27A8A8F8F8F82752FFFFFF2752FFA8FD06F87DFD0BFF7DFD0CF852FD04FF %7DFD0CF87DFD07FF27FD06F8A8FD06FFA8FD0BF852FD05FF52FD0BF87DFF %FFA8FD04F8A8A8FFFF27FF7DF8F8527D27FD07FFA82727F8F8F852FD0BFF %A8FD0DF852FFFFFF7DFD0DF8FD06FFA8FD07F87DFD06FFFD0DF87DFFFFFF %52FD0DF8A8FF52F8F8F827FF27FF7D52FF7DF8F8F8FF2727A8FF7DA8A8FF %7D5252FD04F8FD0BFF7DFD04F87D7D7D5252FD05F87DFFFF7DFD04F8FD04 %7D27FD04F852FD05FF52FD07F827FD05FF27FD04F8277DA8A87DFD05F8FF %FF7DFD05F8527DA87D27FD05F8FF52F8F8F87DFF52FFA852FF52F8F8F8A8 %FF5252F8F8F82752A8A87DFD04F8A8FD0AFFA8F8F8F827FD05FFA8FD05F8 %FFFF7DF8F8F827FD05FF27F8F8F852FD05FF27F8F8F852FD04F8A8FFFFFF %A8FD04F852FD05FFA8F8F852FFFFFF27FD04F8A8FD05FF7DFD04F87DFD04 %F8A8FF27FF7D52FF525227F8277DA8A827FD05F827FD05F87DFD0AFF7DFD %04F8FD06FF7DFD04F87DFF7DFD04F8FD05FFFD04F852FD04FFA8FD04F8A8 %27F8F8F852FFFFFF52FD04F8A8FD06FFA8A8FFFFFF7DFD04F87DFD07FF27 %F8F8F827FD04F8FFA852FFA852FF52FFFFA87D7D277DA82727FD09F852FD %0AFFA8F8F8F827FD06FFA8FD04F87DFF7DF8F8F8277DA87DA852FD04F87D %FD04FF27F8F8F827FF52FD04F8FFFFFF27F8F8F827FD0CFF7DFD04F8A8FD %07FF52FD07F827FFFF27FF7D52FF52F87DA8FFFFFF27FF7D2727FD08F852 %FD0AFF7DFD04F8FD07FFFD04F852FF7DFD0DF8A8FFFFFFA8FD04F87DFFA8 %FD04F87DFFA827F8F8F852FD0CFF52FD04F8FD08FF7DFD08F8FFFF52FFA8 %52FF7D27522752FFFFA8A8FF275227FD07F852FD0AFFA8F8F8F827FD07FF %27F8F8F87DFFA8FD0CF87DFD04FF7DFD04F8A8FFFF27F8F8F852FFFF27F8 %F8F852FD0CFF7DF8F8F827FD08FF7DFD08F8A8FF27A8A827FF7D52FF7D27 %FD05FF527D7DFD07F87DFD0AFF7DFD04F8FD06FFA8FD04F87DFF7DFD0AF8 %277DFD05FF27F8F8F827A8A8FF52FD04F8FFFF52F8F8F827FD0CFF7DFD04 %F8A8FD07FF52FD04F827F8F8F8A8FF527DFF27FFFF52FFFF52A8FD04FF27 %525227FD06F87DFD0AFFA8F8F8F827FD06FF27FD04F8FFFF7DFD04F8527D %FD04F827FD05FFA8FD04F827F8F8F827FD04F87DFF7DFD04F87DFD06FF27 %52A8FFFFFFFD04F827FD07FFFD04F82727F8F8F852FF5252FF5252FF277D %FFFF7DFD04FF277DA827FD06F8A8FD0AFF7DFD04F8FFFFFFA8A827FD04F8 %52FFFF7DFD04F8FFFF7DFD04F87DFD04FF52FD0DF827FFFFFD05F87DFD04 %FF52F8F8F852FFFF52FD04F852FD04FFA8FD05F8A87DF8F8F827FFA827FF %7D52FFA827FD06FFA8F8525227FD05F827FD0BFFA8F8F8F8FD0527FD06F8 %A8FFFF7DF8F8F827FFFFFF27F8F8F827FD04FFFD0FF8A8FF7DFD05F82752 %5227FD04F827FFFFA8FD06F8525252FD05F852FFA8FD04F8A8FF27A8FF27 %A8FF277DFD05FF27A8FFFF27FD05F852FD0BFF7DFD0DF87DFFFFFF7DFD04 %F8FFFFFF52FD04F87DFFFF7DFD04F827FD0652FD04F852FFFF52FD0CF8A8 %FFFFFF7DFD0CF827A8FFFF52F8F8F827FF527DFF7D52FF7D27FD04FF2727 %7DA852FD06F8A8FD0BFFA8FD0BF827A8FD04FF7DF8F8F827FD04FFFD05F8 %FFFF52FD04F8A8FD06FF27F8F8F827FFFFFF7DFD09F827A8FD05FF7D27FD %09F852FD05FFFD04F827FF27FFA827A8FF5252FF7DF87DA87D27FD06F852 %FD0CFF7DFD08F82752A8FD06FF7DFD04F8FD04FF7DFD04F87DFFFD04F827 %FD07FF52FD04F87DFFFFFFA82727FD05F852A8FD07FFA87DFD06F8277DFD %06FF7DFD04F827277DFF5252FFFF2727525252FFA827FD05F827FD48FFA8 %A8A8FD0DFFA8A87DA8FD0AFF27FD05F827A8FF27A8FFFFF87DFF27FD08F8 %7DFD67FF27FD05F8275252F8FFFFFF2727FD08F87DFD68FFA827FD09F87D %7D7DFD08F852FD6BFF52FD11F8277DFD6DFFA827FD0EF852A8FD70FF7D52 %FD09F82752FD76FF7D7D5252527D7DA8FD6BFFFF %%EndData endstream endobj 19 0 obj <>stream +%AI12_CompressedDataxܽz*(1眳If&zk?URuӉ0gl/*TYUR2q~-;FVqX2Y5*No5NZaGtWs4*hoFFW2:UVď:󝎧9h5eP<{;(}vzHRex./y^/`JJ|v:vWĸ*U /EN]8]9]8tx~E^DIԠ+5ǫ&[Ԇߍש5bW?vo*F;ӪԾb2l5;ߕAW^x6[wxU o˛>g||Ó`˽vzl|4N_FNf&8UEV9.°sDWo 99Jg<6~&&i-ˋb.iW-$Ii؟Ɉ}ڟ_߫NA1\ (uHѿݴNQ|ҩ7Z}UHuQuZ{̈́Kx\@: @0ܷ毷(} Vy6κuL%+z\Q82x8sR\PȘR\TQ_t5hڰj&nfȁF'xČ +{$|kjV5%$.'"HD }׬t +q!kA G} d.V XiJYuӲxoaߑW[CyAs`tMF! ܐ@S²~^oqi53OA66k՟Efޭ7A0y`+ @I(j4lN|w_}V 2աL4:`U7h} XMWc'akO+ߍJ,a6g111}\Ƹ*`K ++ :ZQu^M w$Ț.+udp7/L/7<I酋e Sia// Ȟm(+-0dm Ol8wcga;v5GpALBA2=xvݥGӳ" ՟(HN'`LƯݭ2D.^uZb!|7:KӎCru#>3`nרHTe +NWwn vπ㹸Ɖ>4qS-"[,y(5VI7Epivp显/%98nV0A#ogق 9ǭϋWC:t1ZKoLܫvt{k?TSWiڟGYNeA4m\|DžxբCEQ[5Imn9{Zz[6z0a$`\w% Geo5~j3ԣztT^5jvg8`ONŠjgɺ:64e[s87 +(`հo ʝgT p_4df.z\I5r]ıiFMMGdE/V5-jvAb &}ee e5_ "Ibukz߰M~n7Q+ַJt;UQ㥩٢w}LB7Ju+5˰|4b 0\R4㓱[VDoG{W+A3bt,vjx +XHx%TGM>/qHڂ(g2&=;60Wհ)wjOܼGCҷ,Pg92NфIڔ0;ӧ>(qyF IaH=2)qzmP זZy;fݩ_n@Xjvܿ0@?F"CGi7 +p +[#Q S)GUYi2'doq L:T1 -؝ +ໂװͻ_9ί_95dosRn5sg~tFTv{9fSB긟k + ?h4<[<^H~۪oC&4؄5 ic@HZg0ʌxAZL/-P=0[xU'-xzq(ۍm_v k[%LL3Q Άɍa:jzGu% 6gCA%gd$!4I!N>m)z +T~7cf^Ow5-hӝ3eᅭWe%cq5#j-`~uHXk&'qAn^Jei0=6|FM4sjvc&1rG}Kj8& /:zJqTkׄlI?,5&wEGEuL\߸w~d 1u10y07I!4Z6)P0Q3Pu=f\_$]LX+{@16֣A%w"gއg`kW%zo5vBvp|Z}\{ApmQIh&3v&+]RlbJBe;x TJ/(8c"zӫD na4z Z[IoJl΄ u 4ǃsqx8*gWBUiq>>6N6)\d:;ƻ@YqVvQ`O0]&*Vu2Ql~]"Q/ + $2u~g"^GXȚ1 +F.AՎ14uPĒEF\O WI=ԮG|voG_ &H3CuP)u2lP9 O("qDqA_2vt]rnc%9D VgP+4ID8j\^na;Ye㜧wk`Kڟܨ~q[!q|&F"_%ͯDQO|6\"3\JܗYD)^NR_J_|?gN[nQ%{͍ja{z}7\(cẼQبm@ƛ`Nד+Z +g[]N_Dzĩ٩I+\^ ӉsyObIl5VcAhO'}F &8sIʉ0XXR>W^/>nt~yeOPy}QJ6XVz~@{/?ŪrY +^@a7}IO-:]/{n!U]|&@0`2T_~@g|s4ϕɳɥ\α/Хc7p@@#` ~(uFVuuazZSZk\](rZr[%4&?@_ק@%4tUf@Wx hiKX3+WֹSOsu[8ʕ_^(d\Wz +Kjȱ`~e˘C6bSi}*;>sjG#@©$U?=V|*Wĝ,.=Y;z$=j\Ч,w(s=o>=S@o@>/ kE(= XLޔ7v|޾ wuTzz @1~eoe~ 2wU&m~zNs.]!@ARi@b42*,m3=ޗW teDӼ%÷ks~gq:ʸfE@w \o64G\Xt5Zf +t?:ʟ+]VGN (+6s~n+^1^\4ޯzkTu!,vVO^o kXL1iP]o3o۟s{`&,_.o]S cǙzk-26WZ__ӷ~tW7o-?~[=jx[ʘVۻd5\Zݰߎ`=.༻Vعzk`kŚP6}իc-&}N ߷BBXHZv79\o3-m1{³ [9vq} Easƺf795 C<'ʉe܁7A*a xSn愥 $!6EdokpSDk/y?D @n77imsdšY>.|*7mn} +ʿN +5WZgJW PtZ_\?]Y~2@@P'5Wх`^}>tܗz9W;Ez"b/E kǚ6t[wpKumޟƧiН!/v`υ =/{DZ l0ߜ_]lvSk'*@f7eGaS{*ت"dl&?+'1Mh`j])#Bo'(%?NyYKe9sp] #/2(ta;II.lH_אbIcPo% ݓai;#6@%A29rc ]И{HD~Wཆ5e{~G[A\BCethgrXgQ}-k)k'qBq> Ky'DSmc}siIWc"3=q.・] >Y] ܙQ}:\IbyS{pqLMܺ> F4"g(LY5s.rۙzB +3c)aӋ02t~|d6Lڱ(q̻0:sʯD0p%~<s1vF$cjwA?v{6*e⒂lgg֠\{ܫ& ﷹ&?b,IftI{:.>4} _ҕki뷺{}RLSNRx5:٥1! :(ZH/l"w_;ؠX;]gEYuB=;1a,Įcoah`HDP{#`-X-6u?+x#v?Qol͌+w"80⏎bk408%v6ZɶMm Jt R m9@u.05?1t" 馦侴{^ΆOH7j0;5ad8cC# A2$X8GaK#KSϖ}wK`i3F}rg]DBd,.._y'YIsD|"$@s퐬gOdiFHAY-M35*1$ +olCZ24A t#L8!GqC~pC"&,{ۖ%vQ48M!ci(pS6%V/ՠS֍N!jˑ[N4bɈRhQmJ5DJ8Uo/Pl$# @̛;L?- ] %GeqjY㛔0\yʽ9#8t6x+v5zdd.JufRf+e\[m'mO}R/HdolA|ʹݨ5trzVБSfPC\AKΦnJk+Zp5t* b +:Zp:OVW$5ttWٵoWСE [D9+ǯUel:2U/l]o*L'Wi4b)^ Xd.vȄmTߚĕ4*>-`T Ev}+"4]g;?gS~Z:"1 |n&Ki=B5.bŔpV"nz1+R'u=\E=eM^.9$Sy'CSoulW֣z9dV,is"mۉV%za{t* (&HLTNYl.I%2cExFkń YlxA;O +ep#*5Kp:k[ Ƌ39 V B +>( ㏆`G:1IưP{ԋE˥_dɱH̽yNPZz ƫHME,*RYTb,*R+RwE1[w##aeh lx׊m;M)})̴>>>i)7f] +ѯ.yPӔdDLX +l2A+_t%HwFƯt\;6d=,I]~9S“,G %o.(>‰iZ#g}F>q+9$ 27>Z|}[_כR|>K¾r}XՊŝ^Bp5Q1'g5V@z6bQtN3T\N':~nvr=2zǿ/ծ} P}f]WM[`>TPY_SoSPwP] yqWa%{bn/ŵ7?#j' :_X}kz!4Ta[4,m&6Hb'8g#&!L$AE8Мo~Mr^ +#O)Ô"800}9i:lI aFg9ҸɔCrEF5Dv+[1j:w3ej:yj"<9V5~,l馊ZGr><(yj:`9yt^t^fj:/96j:Z:kufta訥3mgWMUKgafUM絺$j=j:]YWy )ƌg6t^yTt^t$t^],.tg`pLEij,joʛΫњiX%~5#Wy1dSWy҅+:A5 +=a5;]._鋎7;VyM}Xt!8NcAԣBk*b^?a΢?:obE7!5k̒3vR<:W9 iG.jy!x +\ ?b!!?D#Pw]z4(Jlke>tcl|k".◠")]s7^~ܹN n5w7M)u͝+/so_s\ԑ9qO: G*b4y%6SfkM +&+*rUq&=J* [M=1#TN"hDExhjpmo2aXH6PY\HPYr"fR8b<i$IE=3-r'M{ڳ:<+Th3M{Q:&J/zX7T=8W!r)tv\1 <&q ~>]cB;io^fqJN.Ȉq8ҍޓX0v!CX}'Ά ]7M^_9 w6 wtq1+'')oz6nog1oҙz熻wMQ4fH +kܷLxZ[҃+OfPϹ"PL>r$fvz]^P6\M+="XELQ8gEث1ɺp5=XMؕ;3GcgQ?nX;qeLAELo=_=KWz?~7 =K$Rc~sٙ{fWccck\?\hޔ7b.ﻁKtW:K#C=5.ñsBiau/JëVzQ9.ׅ͹U<$b(;ݺd:lyjU%﫼/P-U) e^[stoH~jt@iڹ__R{LrLZ>i*?j!h2NK~po@/;J+@/]@iޅEG@wwoU]+'swm)=r˫c&a;kڮP9,b$ UN;wJQ&#b\4!6i*!=ژ[6%aFR o&e}|}̟wey:Q'ҽ~59zF/Տx{:i{\刮'xƭ~\#Se{>~q-\U>fZZl{v9<~n+' c3!Ǹ/_9~o0tgA^?ka=ocN^X^cS;89 /xs!tG^?sHtO|RW9ޛ(n}Ha$z.ĎamntklS:6bYC{=r<.p/6zAKSW{eXEYNeK;?;iag$+u>o/hkœKIsRM;)r|'\~lկNƩsjZ+ˣXk~il?oOVNw[K bjOIz:8H?矤sc,-ܼM2 6..ms坣v)޻;Rէs:c},{;xٜ>.]{<~ .ɫ.xO.E,zB"pR|zsú, +pUOԱ,M W)櫝IMbPNr :<;8 }`jE;jēd慉M%Yˍ{r}fe^9-|VwW@[{su{KD1h̗ŌkljUs/ݽevoLâo=9qA +ssK'>Ebǀ _eR  _7VWbO=Z̙?+˻‰sJrXN+Ko9У4JTqfȲ/^Ն"Ͼ?(X ɞZ||n9~ozk O|ƒn}}3kBs +yq$~q hD8,P/ ;˭߁D. +cB8'A4z7TY,9j?EwTl;8sKi*%K~¬ed`ǖy:g\3aMAZF¼Xs +krfnc0w~/':(e?%_׳u {Ǡx󃭣¾|us{_bZ+ܿ_Hww%ncɉcIoQ-wϥԷUkVmb(zHd ]1zZRDckG gjBQy<:>= B&>tbɱk!ǦkBcQ9sIc2H6̙JpR0w<TNRb FNqd dY"K-]l)& C8L^ fv6N18xHJOuByVX91_COE=;'& r2XrFĿ 0UjX+_oI!)sC*^ +*Kb3񔎠d_F`ft/5OC?#O{^ +#˅VwN>A?r?ո|/cQ{'b ˱kĔ^b,7xb}7b}'MA^yj՝<JCݥ'?SՅg2'8Z(xeQ |\X(xQsHҺ&E Ļ)oG>׉B$l~M$,'HZH0%dIP`Wl L&l$$b:Z=>P}Cx !]2R@h]n8S%X.y?1 A +iq,Li94nVDj.^]xJϔ]iѹ_C,9҅>XF+dՁ/+c`;`@:`Ű0S klj΋cO\FtzPL]87cv/?v~Fon鸾υ;X=TfbXT2B dt NuW=I$4* @cQ-O*uLW8~RȽ ^ipd7]y3> X^v'ՙcoocZ+ /VYQx_^IV\]8v-"sVLҭkgBNs죥RdK}.lٴrF5NȑR 9u׌XmFZ>trx1E,EeMc^bX4\olI;ili4K!4cK b9c4 .'S#Oe*C)S#/eZ\#@%8h~O4Xy1g>ifϙ*+#Yƃm|vq* 4@7,zrfIēM{:w0-;wVb.g Y>PhG$8̞ +jd9?9Ԇr:]'$ߗaB 佲{>u 1B v뼘!D;?Ț>pϏs4޸q~%'?=$B;g/K6vp¸SZ;|p+ / l 7kO[.hxriج[lע}$xD!izIOX{vSe%2aQ'U$ D> [iьZPnq|V*ƪ*jd9_ugnݔI42r|M﮳8xʓu9G_3)3Hf{U_ooK4) M.RƖh3HBD(F}6zJvfyȫ3>W"gzȫ4%%ٌŒCۮd\5.6vqO?ÿ-.2|q5"m|:~܎qn,/fm+?U|tr|sPk {*o077~hĆ>Ve:_oxw'.^G1ҤSt?Y˩ +vr$H&'S$AtY:'[#HM/uMUuA8Ax{ѵ,hb8&ZӠ9Ul#I9 +:kX>I3<5n>A2/BhAV ,hAX3҆(a6,FG֊1k2dH(<Ef 2ƣ*0*K6aM%T]! +XI5;#A/ yI* $0D '.RSHDˠF ဒp,DU@U"E8 +&, Ou4u$ +SQLJspr +Nɚ+Tb|Ɣ +] >,ft+$nJ^2ZK0(KQ8:2A\N*Jц#P D)QsWĘUQg ;F4Ѝ. GڠRUG;-! %h0 [Hf1G)e#&I惎:Z\GQfŴHKk*4"D0=Q%S; +@~h80Q@5bAY0LšfE R a㒢2*@8 [-D8H8 `5ȕ']"? A2y`j`oFelNÀ +<r1E l{#䐲`.\InH M-P$0"V5s:a ٶ)5ݱ/2@ +: -Nh,(Db;x(# U2E ŃD*tEHzq8Bi *BBStƤcvh#Mq(A/@ %@Z2Z>T c BtTF)OW0B?JnR+2/A0MSc &U7&(Q@2"DOMe GEEeppLh XAࢠ=Ǔ:`8BCă`M"Ҵ6v| H@b` hDcrhAvDMRD6~lɖ+XýXd'qVcAqCb =EY -D%"1-d8`% %T2ם%~"(n3zw\yQ(f8?EG'B/YLU!V7L-Grm*븵 $9 %D3p0x$U< +(* RV8٘Cģˇ^)lu0H97D\Bd˯˜j(AP4=mցu! bqz8fZfܘ6*nQԒ6@3ΔtF-3}PRuH\ H#(h~&Q8*[Du8a{Ƹ& Rhj 8[7"FLm|2h!m4\#T:1Pӿ +vHrg@  +hca=TܫtlDhaq T#du",%Q LDtآW`F#y$a ' -acNNvJsh >z&LQ4d=kAdXEQ% *bQ[ r:M3v`P22S&,3rfرHhpD50MBT(?A&8Bp8Zފ7b0HÚ6eJv=Y'oPƸUUYez`6i8hL=~"2v &X 11cZ~E+o䎣} +Dű֧l +*kx' <Ǟ3\m6/~GtrSnE1cC*JNng4 +|r\r( jca<:28u4r{<[ +`׏]οț])YOINQ¾<E d^쭺}kueԑ6#ZPfQϵurr'&"l{HGQ9Lž6+!\^{3Wپ%TS:U6{5Cm5T#ayxzcwUl ihA?T" -gٙ1h'l7j8%]9E,"NME##Tbȳ(GٴT84ƀf}"\hMf?Gm"s503/A-i T4wW3):UbO9.>OРӞ(~nc˃yE:sí/hB5WZ>"ަ=*/A)̑)ZBEP-^JGdkoKQfe/6;yQQW<=z@f̢3 {}{n+=>LvͻJk`靪T~pU%/6b*b#洵R vEX->q#W55pϷi奿?݋3u00W7_(,$N7c64,',hCAƗoؘY~bA0wwd,<g5=}/wvK-$ "$Xg (**U;(+@k&] 7Xfe%S(i9ۮD=8'A|rVJhUYE+oziWʖ5 lG P6'SI~h< f=Gx4Ө`+ cZ6wP""D`k$K +~H/ΰfVe<ϝf~Ī@E w{ČȈ+5L'֮"XN9Z]Ѻ`.0Ę.#wMl`>{U篥{Ucspýzn_Bg*4{glcS+> |OiilM'U2AqBNSC /^bf:Ϯ3sCz +Pk5Nc˘B~>O"n/LtZyJܮWxt#0j;\ +zZ">*032}/*v]JlUŮtλˁqJfa΃lCB%{ y4'YkS3ϰ|T^=_һݹ7/^O)غK@VP{)'qp;ASG#PwyMm +&[egEij`QJr،xAJ)jAmSzjءӭ(M3ibߣWnl\~lez;`&,u;NAh}7eUzEuܙ-k|Kmn! z5į76Yn%"FrUkc?V|^UER>\G퓀5TT8;?")# n+ZW'arI Njκi`x [:y;$HWP$zvN}*?.q/X]ei.7QOjfqa_r\Hh3N(i_呂զ ?lRAC hrdu`UA`K" i({ U42/(:#9w661g"ȾIM#DWvVB+E쁻 dOYSēs$`2 GP +#g$q/%?l9W~F|Wbԟ.vm|1(,楟#FO̫٪]7(0Kh\43W%^=0QK順D@ޛOX:> 84' ?C:p/4NFc .a躜F`jv+.q8Md7j#Zc"O:^ėS2)2ű|k i kM"d +%9PF 2=cI`;\7J?D+BrLOܩm˘$Uΰ`榒D<(SN*=w6[ +PQɷp`'I?>0!6d IyKNZ27Mjwdi κxg2ã͚?`X*]k dg\eq6Z\׃ 5Fȶ&uG߰ _bc~]"õfEζ^ S[]사1򱍿UvChZ<0]$u-ް(@fYU#x4._5t#Y_)d\oz^F ę~~hnML(ˣmvbYƮd؟j%edkCA]Gfmqްes h /4Y0O^}:w{^e 0R\F87iFi ̣ +WfNaDFB,*@I/8E7/]ظllv|_'sネjEJlw&V3|cl3TgfX-E rEqB,ǚs1rqpjE/!0C}Xxb|l!mï\SϜl="m%e{c{BjbAiUi. ڼs5OZG6oXDӹWyY]ށvCi 7?oww1h9,M:5,`ݡTl찯á1xCajj"G~Yo$1'{5TS6Q"N6]Np-؟v^84e\,x#cu +ř\z)kkӜx}db-vKYiL8:i)0x_=+>#85W^A=u0}c/ޯCNֈuUO| >WM_-*K)ynޡXܔ@V#9dSn}kƻZad̎0Y3Kikpɞ%~Â;7:JHCiգ2ʰ2e/)HLЂ| mDo{.{?#)%+-KE PGuM@jy`;sͮaKJj*YV`V^FwM-iyS)-Si| [9XfunP3NC4z7%l/nf1sk!+Wawq ^yۛ(d): +z|ɦm-^HJNig@8i}csr- v/BU$T {'K]*,p|+͕Xa- k)2NW'49oncY˪R-|׀E "[8C5n幓ZoM(Q# +RQF-0d鎉əF^{`jTa2߷:4!l}MK^xs^k9: Z*Zȁ L8N}| +B&/?ŏ^:hҁJ ޲4>Z!fwhA>6%Na*oicb K׆s w[/q:CƎNCmf7LIeo6 8.D}y n*[ 0f?9GhʘL֧-O7s=Y7 _$$MlBJ*VЃD +gN:b^;u*]2]wr9re+Fؔ׳gSƁһ:ΌyOq`;g"JB<+FLXR i8ӵ6;AvK;JoȢA[hx%OST=d`#[BqK&?k~/SP*i8X](<`p)!,.jS{icw*jv]Y'6p@ dw,vKsX`mLLNrzCOR.*-)ǂxrb8 $r%|P{Q4M4+Xl5Я i8EPm1PLAvzNCR8:c#EոTb e^OLx*1,BPxV_,*^trd"JgwqlձD[ ڛ+^bU'.(-T3ДnC.k…pthTݛRߍPQo7}%[ٹ/Aq"װԀ}q4aq XuĨ'0B1K|r3# SykA+ ډ]\3HMDA-׸TTlI50Ub1OK?ۄ'P9gsIEn}."rL TcoC2P|ɿ+I~9S+c";vb a>@RBŤ!#`c;#8jj2"Wxpf 0ur0vA~ ܮ1!@SLޜV{0"K;H>6oϮY!J#@phkbPajxo9.C#ʮqo\4oCiZ}W+ז[Z6|&8dP؅^e (Bcz@LD"bY N>98c8ⰵxQyTԱۍX3l2G&nKOG6 !.swMuv4M~ԓ;Bi3,J{>m܂r <4 :\A;b8Gl +ե-usHJ\xN U#g3LWE۱E h:WDS670M~(aV0xuu`{0nWgv|ftxH* +ZX|; #p lp ?飖x7ADMWsRDAح,Z"!߅ޒ3^yqd>36>!YahO8cӞ-JBQ&"VNUp[|PAbCxI(C9˝"yW+;P)܂̛f"{ +u#u e.G1=+2}dwh~/KprHTׁD.2Rw=x+4B#bMܕsj,TTnױj9M +k޼շٹI"*vOw8s?=zAZn\,Y9AD]!~$5Ŭ> +ew;@ˋN⿁28/|vFbP`2wG,"P3 س^ #J2E$D9-ۋs66e&=ʝHS4U*_q B.uTQ)mT-Lؘs|)A3Mڗ=06z q2sst׫1}mWgmcg5d9f4eo,%̲պ(yɪ c(be=DI{ F<'"U>C.*'S36d8nGN2 +dԯd>, +I]bG\1MJ0l/$HU+ӊlhkΥl My)PW]8{|EDX[[uA8v:Ո/d5 l + fQ , }hY0${+dٛSfۉnN+LF~SƹYۇI dkՠViaU6l T$JWI4z&^ڭpx,pνǙ0z , t+0t*夝 ؕW:%ȿK` xɊ|iq +V?ŶG>lbq/VIZT9hk5A"C7gv$Z=a$_)\a#Y%VLf>cf(Cb)s,,#_'MLǢE9'YJôt7_drA\ǂ,F:t-Su29&6|z%vH`REP*`1)IXI8w|8"¯?l"k%^i5K7~y3<ߊ,auvS,ρ_ t,i-mE/PD윐b;E&_\+r;+H-zKa9a{jڶAƄM X$=T$hSX:`̒NzQ?nDW +"Iʢ:zwLHR&q nRU=|>҂{O}R,o1`>dyƷ6{\}8+GoX`E,y3ٴlUz9xpt5} a摶ef`A+4$tWbhҵ_@c٨{[,Kٻ$(vgJ Z.l{,fhܒ> 𽟊y}ū~ŪQ{GV29ޯ$i-6Ce}`l\sjׁFw0@)ؤv>u~Y˱)R5qa_0 weK-Yz 3ƩM|%CeGԫSmQ r.ױKo/-ج:zүqJzgsݳd{mЧӑ94tų Fx]v{LWl*? +E =Y.C('UK':B&"R淟M,cJ5g%FFhuIٶ)*STv/O]jTd $o/|vH+ +碪[w'E,qAD!on!Y@S2@c&WNY$t|¤^/I(#JU$%Lmsd Ш%x,c^SsXPem>+fgb%,PI- \$0;4SLq{*j\M7EQ $HQ|ſ1x* +q \3P3O+Ь"z>HC:@{$nm,va ժI;A(<2 +`=< H+;``xJb +XDUh:&|C~y"}iyY$NX()|:Wj=QqTEX=9;+c\]ƨ<ޛ6Kjc5FV]U}, ‰'%CWħ8k+>l]T2O {@,# ͦMROqS(Y"זCMs2`Ov/u/CHLZEwdD1LtYTUdY;(=Ǜ""Ԛc~v\T% x)~zqKxM.a9jC1I`lTAe?f /vpA)e 8/ILC{fɯ`'^%<),f%9*FEqa.^Ҏ2{iic iQG,^{q=p!b\胓v:mH:Mw&<㝂r)!Wa +Jmm``U&Zk Pc )o *#덓ovոbKLu-r*{׋S_xc-]ᴘ89A7j:Ӛ2_1[@}Ԣ]p]vv|QKBjgW^P07,5N_g*]fu7O7Vnp[,R&mo5zHnpet-^T9!ޗSKonR +u4}s-!]v~ +Kam8## 9 nj^Qt 11QnfV$#;#;crvDG EctXcXLd)w:,dƏțqM(jOA|\>R:z6z-w R`px +@HOD6U~õ*G_sϱzȻvt814nqlaЯ|o{~ +IZ9H ыajLvF^[ t^3Q/QFJD Q,-H{ $_>WPbtgl'|܅_.ֺxd/%b?b14#F;+R܆G&}!?W*NmtSU1x!Eb"WH}e61C{fKb;[,jM*^t)Oj(q5bS.b_VJ9D´n=y/WnSjE4'U4=eEVbtG<8'ՠz0bs/6s#EioLa~֡ZBk [bk(zM{lY/dmoy-)38%.l{̧ #l$-?O3*GtZJ)9BMj0k-KS]z-P .++s4ʏ3Em^ g>X~uv[ʲWwk7;Z)Q]#:E+4De7Klts -%ޮ 6$c 9_Fˆ`sQ4ڇQn@0꬜,1tBluMoY;؁'ړI_)v'(duZ'o=@;Jm[czwX[_;C 5$śN\UJ'U)tJ;cM4 Srйm[aE@e>N0K 8Is/:Pi3N:?iוYf9k;rh2r8N9бP "`V2`٭ ‘%:٭? FP.mOKa/$5'5d3}?ƒo*sq S=gT=#*,>۫kg7~bq=Yy.ҟbQLN~Ls0';7 6_Fծ,;a8|?,B$ul;g`|1KݽMGk#L}|8M2$yv&:fc VYy8(vtCk m'NռvJLKCVq`%Z~bHŒQbs|-4,*Lt/^1U4 P=>:p&AjDK$n3y>}%e8ʄlk{Xێ^Φ͛>y<"&Ԥ.Lm41wR~yyoS舅wBHx-'!b,uc[xBD0Aa-8'9aA/u=#\yVxݦ6u@*LaǂR=ӬJ bnE5缡 +М΄^?.?hN:&/Rv3ggYtprQ&nb8(*|g/.]Hr{/=\8Je$X׈X?k>MsQ-k\kN..GdGRHj:uڞEsP35"aŎXXbGx#㨻8_]rʯR)e'[KL)c(T~s]϶)Pk"y( K?=B@o/ȝo&WvAt㽔j|.H^C~jcVy?O~UL*9Esl;lRqcn c[P^'<{j4Joa}}08Rgqgŭ`E5J^|JO9cјP @)uҢG=%EZMÉXOڶ=$x\vdla'(bT%Ҏq&TĆ (2(5wR$88euu|c!mA?5>a L Ä g}Ә@}ŨYs(y\)+ +t妃'rk=K{3~yͥyIj;l řרr?W`G9Db☘ɞWE +*eoRz +ZE]k'Io] +.2]^ij=[0Xl1[}[d@%0M~V8=ag vAN8kzx᝹h׃K +Y7aQ'm-6US 9&4'gG,i5dSl c\l7$Aޑ0щ j5RV V^1XЬgUYoΖyTܔhy!|D +}ÂqcV. ⛥؂d5ˢD]3Jy]p[[bxYT /RCr ήy|C-,dkgK";c_IK/vzݲitNl"Ϗ̝[Ε௿U^M`B*b08 E8owmY@6Iq98 +=T%ck{dJ׽kzdW2.hSc|D%EcS+IB5@/-b=3(`=iWȠ|< ,G;Mv72-eB|æi5NиBT}UWs(0U&$7MfIRJS;a¥l8M ,̣,T,;qp#Խ+F ~2W"6I((%Qsʑ7 #' '^?  7yx"MU:nrQ}ۖ znůc-R#'$[R#&&+1K6iRi*013E:7`Y@ 7w$7I&fq%6uHWw&{pX$Ux@[+iYsjKcX|҈ShMR,۾х>; SX%@ +p@5ϥ-+%QJeCXRZ̹q4B gD8NBܵ(#}& +nM0k# + br&t8wM +4gbH Vyc1Z3WdVjh@DRcM6C!Tg udhQ9{YONτ#JC{h?k +@/'~H*Xb +2ST1[.sAg&+m +-*88J~p}&z<'r1H!HZ>y&>3?r,Q4̙X0'ߴ)Q\Jj7غkN}=Μx-uXSHrҷ nd5jYlW})V=YdtFbu_n% -赴T^5SSƏ b׼̶֣DBNJ<ƽR{0>-UC{ hѩLqaկ54MpG o/: a91:w s֜ؗ0Oq8@H6zĿׇ`7+FdiؗZN(H8uXJrlRM痈<:Vaől9"a9Xړͧ>~ ioewIo>R̅X.%/4G.9,)1ANS>9KQKgbBT,%Ku `Wi8F`=9q5InadP6|e|- +ɓ O"E-#5! +)McYő +whh#2>I`¨$akU3uR ++89,\ܛQQ1E/ʔV#6PKfqG1f΄sx#-0gՀA3^ZDK]\-ҶE-mQB=Rف[M1ܶY$@ +TW N?ĘCu*gvFU'q& ;ҏU[,EöDjH;8)ҁjlR]^t~re?.n`߳9*ԁԇ%j^GW|\@l= ge#w'-ځ۠u>~耪f"tJs] T4aם(9Ab-jM ||@[TAR6Q rZq"C/eiT'>uUUT9?Oe[ ˚2aVi_ϑfYFfW݁!וW[E0AT,je1Cw1N3!˘cLfJ(_mx%oDyƓ5q ړd>C4QO5 N [Y?~g.=-DldkD"^}=s"q:dH4qC{Ee?M]ExW%rf6knU:*9b{U5FX\ G(PaLu= ˷by1-i[j&@1羚KKx^-H4q ^WᏙVX F9l̂L;qD;1qxI&.#+Jj14,geN2Y|~/hx'">t%&yڃ"KQfNGg5}AṀVNTZo=),Uwj0Z,NHXxov ܈ iI1Q0vȳ2k +@$jzz]5 ڪ]#-p%|obԀHK&\.\Er%iJ?sj56Ix m۩\s1N5&43JzEIVXGi2v#m ƭNeR%+W{Ө̒Q~NP`wyDO.rgԄv&sëi!{r˞|׉k\VaYӇ 5&=Bx=X[NDpTzl=A)L}QfPf/'lR .}"4F% Ahdvv1;#n%ȍ3zךL y+ v̕[(`Cc9*+C9O/ =p7-,L5M¸݈mXPNjąu孞tֵ=׍*lU;OG^3_ ;5 nc(<'gY-},-3#ft+ *lIa(q%L'd%lt֤s| +׫_gy>0r&S6S ^_yA +]`M ˱73`IWБL+yPw9tzE,]ojbSlAC4(isv)er;,^YJyx~6`/yiYbt +|rH)+\x]p$FƚbakR-|_H|{d9>Cz^M4.C_JMNhncbIb7C/#?c-x'>Rukh!)o_>4qMJ7 cm"=`UJDT&6IޯCͬv4zlV-1rͷ[\1;nA3ŋSiЬE6%AdGyV}='Tm Y_G|dcY<9J$Qo _"{s:P]=Ae]w^4N^Y|?s ĿnBJDGUDnU[ϨE7T`5є%i,be]; Di+Ztd"fADvW/`{oyR]S͇NI;j1Jn4E%C͗`6Jdkba:J\ub̯ם e¿ɹ$1ly ,#sK?!^`*.U}A qSп:e76"3կ=nw,'ҵ2rl` JPbMAe\;A,pt74zvuWM:* zp_Izu(viٷ[ݯuaG`K"\pQl;t",,{,L0v!ډ.;"Q%oκ&XGzljo%2{up3_4!uy6dAĆC> ^bUs\έy CdwxpN~#[-{rYujW-*n aQN֎)!˱78~3 +BJug,P4s/wmrܯYa|fsڕEb˴յAYŔ2KPBO߷s6e6&574(Vn(j+ٶmR kAl׆>+g7E{[!9r4ZfF6O|O`2ԍ<1ǥ-eۣqv]b1aj7{@b/ \Me\"d6uUD=pb(SG| ɆYY] k!D0s]y Ȃ s|['E*BleޛǻLsII hBA ne&f+?1ڮRW^B՛r̟ cyE4d[B%ܟx fkbe}mZeze:Ih̍SxP"GBUuPZ6|.dI&N̛}\d"?,M4mH y81&yRX0G:{v'T[z L =: owiMm .1IEZ/^&gj̓ dcVx Lg'Q[K&W *MڿH\ĨWpݽ] j$sGS$kn28AGH:~ ,Ke?jH2PXaqE_kΖɠh8?8+o:Y1 +e=(iy+Xl +qk✂'|ϥEGq@&ں\Ņ|_s]RkPBq=xN@{/In1I$C@FZ `jV4cɹ8( +`څ#XPǎ3%f}{q)?(H, gt7 tĉ}'5Y;)axTTNl(++Ń0-z`YOu0܊6:",9SSؑ_ӰI;T W4%V8>/ I̲-:C^ñY=#c-f.x' 9ɔ,'v WSl;Ş;dGR(34r :O +ó+pND2 lbVK~؉6U[V_](|ip/"φ0gZU4kDH%J~BnX.ZHy?U};e'#'γh;{s%<-Q7f}~q*ʙ&8 a=7Ol#&@|vA&.GN+t h&ȶz6ʝa>Ș+; RS>gH +1}qo ~.MD tB{aFy(\yc18A:?^Im +,%(Y( d~/=; dޫqA;\ 2jM*qw^W8uܔ+EWgGL՞\^?h.E/wM|oo_O??o_7.7kp\^ǗO/~׿W?Ï_?߼O?ӏ?'W? endstream endobj 6 0 obj [5 0 R] endobj 20 0 obj <> endobj xref 0 21 0000000000 65535 f +0000000016 00000 n +0000000144 00000 n +0000014358 00000 n +0000000000 00000 f +0000031035 00000 n +0000088517 00000 n +0000014409 00000 n +0000014747 00000 n +0000031334 00000 n +0000031221 00000 n +0000030083 00000 n +0000030474 00000 n +0000030522 00000 n +0000031105 00000 n +0000031136 00000 n +0000031407 00000 n +0000031581 00000 n +0000033000 00000 n +0000038333 00000 n +0000088540 00000 n +trailer <<030446611B2C4A3C977BCB0D4BD19E13>]>> startxref 88739 %%EOF \ No newline at end of file diff --git a/docs/_site/artwork/draco3d-horiz.svg b/docs/_site/artwork/draco3d-horiz.svg new file mode 100644 index 0000000..d648d82 --- /dev/null +++ b/docs/_site/artwork/draco3d-horiz.svg @@ -0,0 +1,323 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_site/artwork/draco3d-mark-180x180.png b/docs/_site/artwork/draco3d-mark-180x180.png new file mode 100644 index 0000000000000000000000000000000000000000..5d138fc2cfcea4bf7b26f172e8be6d5d065f306b GIT binary patch literal 13055 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 N$Ve!PSBe@1{11YYkUIbX literal 0 HcmV?d00001 diff --git a/docs/_site/artwork/draco3d-mark-360x360.png b/docs/_site/artwork/draco3d-mark-360x360.png new file mode 100644 index 0000000000000000000000000000000000000000..4dcf90d841ea86eeb66a895abf01537420b4a6ee GIT binary patch literal 29971 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 literal 0 HcmV?d00001 diff --git a/docs/_site/artwork/draco3d-mark.ai b/docs/_site/artwork/draco3d-mark.ai new file mode 100644 index 0000000..5268690 --- /dev/null +++ b/docs/_site/artwork/draco3d-mark.ai @@ -0,0 +1,364 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[5 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + Adobe Illustrator CC 2015.3 (Macintosh) + 2016-10-31T10:57:44-05:00 + 2016-10-31T10:57:44-05:00 + 2016-10-31T10:57:44-05:00 + + + + 256 + 256 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FUm8y+cvKnle1F15h1a10uEglPrMqoz06iNCebn2UHFXjHmr/nMz8u9NLxaBY3mvTLXjJQW du3+zlDS/wDJLFXlGv8A/OZv5mXzMuk2Wn6RCfsMI3uZh83lb0z/AMi8Vef6v+fP5xaqSbrzZqCc uotJBZjrXpbCHFWK3nmjzNetzvdXvbluvKa4lkNaU6sx7YqlmKuxVM7PzN5ksW5WWq3lq380NxLG dtv2WGKsp0n89/zh0pg1r5t1B+NCBdS/XBtv0uRMMVegaB/zmX+Z1iVXVrTT9Yi25M0TW8x+TwsI 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 q3+UemKvrryt5n0rzPodtrWkmZrC7XlC08MtuxHjwlVCR/lDY9jiqa4qhr3U9NsFVr67htFbZWnk SME+xYjFV9pfWV7F61ncR3MJ29SF1kWvzUkYq57yzS4S2eeNbmTeOEuodgN9lJqcVVsVYz+Y2p22 leVrjUbrzJJ5VtrZkaXVooYLhgCeIj9KeK4DcmYbKvLwOKvnzTvPGv8Am7VZdJ8l/nLcza7L6jaf YanpENpFcso5cEnVOKGgOxj+QxV6l+TnnHW/P35V6iPNGnRX+t6fPeaPqdlKFiiu5oI1bjIArInM Sqj0WlakDtir4FlqJHBT0zyNY9/h36fFU7e+KrMVdirsVfaf/OGPmptR/Ly/0CV+Uug3hMS/y294 DKg/5HLMcVeU/wDOZnmFr/8AM2z0hGrDo+nxqyeE1yzSufpj9PFXgWKuxV2Kvq3/AJwj8pAReYfN s0e7GPS7KSm4ApPcD6aw/dir6nxV8CQkap/zlKGLCSOTziWBZdmij1GoBWndFpvir77xVAeYbprT QNSul+1b2s8q703SNm69umKviP8A5xEtDP8AnNaS0J+q2V3KSO1UEW//ACMxV914q+fv+c1Lsx/l lpVspINxrERbpQrHbXBIP+yK4q+LMVdirsVfdX/OJnnWLX/ytg0mR66h5ckNnMpNWMDkyW7+w4kx j/UxVn35iflh5Q/MDSP0d5htPUaOptL6KiXNuzftRSUP0qaqe4xV81a9/wA4ifmB5Yvoda8larba 1NZSCe3guI0guA6HkoCTGW3kpT9phXwxVMB/zl1+Y/ladtI87eT4zqsAo45y6e7dQHKOlwrA+KfC e2KoHUf+ciPzw8/aPqJ8k6bb6fDZKDexaewudUWJusiJIeZQdC8UVVPcYq+dNS1DU9QvZLrU7ma7 vXP76e5d5JSR/MzksfpxVU0jXNa0a7W80i/uNOu1+zcWsrwyD/ZIVOKvUrP897bzHaQaX+aWk/p6 GCi2fmKxK2us2ncNHKoVJOPXi1Kndq4q9a8ofmh+YPl3Tf0jomoD80/IsNPXZax69p6HtcRHlK3H f4mDA0+0q4q9W8t/mf8AlJ+aekzaPFeW94L2Phd6BqAEVwR1K+k5+PiQDyiLAHvXFW9F/wCcffyf 0TUbTUdM8upb31jMlza3H1i6dkljYOrD1JWrQjodsVZd5b8s6V5etLq102P047y9utQnO1WmvJmm foBsvLiv+SAMVfm354jgi86+YI7en1dNSu1h4mo4CdwtD8sVSTFXYq7FXvn/ADhp5haw/M270hmp DrFhIqp4zWzCVD9EfqYqwD8+NXOq/nD5tuieXDUJLQE+FnS2H4Q4qwLFXYq7FX6Ef843+Xl0P8mv LsRXjNfQtqMxpQsbtzLGf+RRQYq9MxV8Cfl7JHd/85MWUxT4JfMNxKqtvQ+tI6/ccVffeKsf/MP/ AJQDzN/2yr7/AKhnxV8jf84XwCT8175yaGHRrhwPEm4tkp/w+KvtnFXzd/zm7M48neXIBTg+oyO3 jVICB/xM4qwnyb/zjNp3n38l9A8yaJdjTvNEq3YnE5ZrW59K9njTnQM0TBEC8lBG32e+KvE/OX5f +cfJl/8AUvMmlzafISRFK45Qy07xTLyjf/YnFWPYq9E/Iv8ANOX8uvPMGpTFn0W8H1XWYEqSYGNR Iq93ib4h4io74q+2h+dn5RkAjzfpVDvvdRg/cTirIdF82eVtdBOiaxY6oFFW+p3MVxQe/ps1MVQf nXyB5S866S2meY9PjvYKH0ZSOM0LH9uGUfEjfI796jFXxp+af5K+dvye1yDzN5dvZ5tGhlDWOtQf DPbOTQR3IXYcq8eVOD9CBXjirFW/xt+dP5iRrb2lp+ntQRFmNvGtrAEgQB7iYjka/tO25PRR9lcV Sfz/APl15r8h642keYrT0JdzbXKVa3uIwf7yGSg5LvuKAj9oA4qxnFUw0LzBreganFqmiX02n6hD /d3Nu5RwO6mnVT3U7Hvir1Kz88/ll5/kWL8wrI+XPMrfY86aNGESSQfZe9s0HEmvWSMVP+SMVZPd fmV+bH5cWfqad+YmhectFQgW0L3UV7dFT9nnESLpKd19QgYql97/AM5m/mzcW7RQ2mkWbnpPBbTl x8hNPKn3rirwq4nmuJ5J5mLzTM0kjnqzMakn5nFVPFXYq7FWefkRqx0r84fKV0GK89QitSRtteVt j+E2KsW8z3rX3mXVr1t2ur24mJ26ySs3bbviqWYq7FWwCTQbk4q/UTQNMTStC03S0AVLC1htlUdA IY1QAf8AA4qj8VfAn5cQm3/5yXsYGYExeYLmMt2JWWRcVffeKsf/ADD/AOUA8zf9sq+/6hnxV8j/ APOFsyR/mtqCN1l0W4RPmLm2f9SnFX2xir50/wCc2oQfIegzcKlNV4B/Dnbymlffh+GKsw/5xUuD L+R+hIQKQSXsYp4G8lff/g8Vepajpmm6nZyWWpWkN7ZTCkttcxrLE460ZHDKfpGKvI/M/wDziZ+U OtO81raXOiTvuW0+akdf+MUwmQD2UDFWDXn/ADg7pL1+pebZ4enH1rJJqeNeM0OKpZP/AM4N36uB b+cIpE2qZLBoz77Cd/14qw7zT/zir+bflEfpfQ5Y9YFp+9WXS5JI72Pj+0sTBHJ8PTZm9sVZX+SX /OVOrWeoweWvzEmM9pI4hg12UcZ7d68Qt1t8aV2Ln4l/aqOir6vvLOw1KwmtLuGO7sbuMxzQyAPH JG4oVYGoKkHFXwz+cv5Y65+TXnux17y1PLFpEs31jQ74Es8EqbvbSnvQdK/bTrX4sVSzVda/ND8/ vPNpapCks8MfG3tYeUdlZQniJZnLFyoYgFmJLNsor8K4qkX5q/lN5m/LfXhpurqJ7S4BfTtTiBEN wgpypX7LpX4kO49wQSqwnFXYq7FXYq7FXYq7FXYqmflm8Nj5k0m9U0a1vLeYEUrWOVW7/LFUsxV2 KuxVMvLcKT+YtKgevCW8gRqdaNKoNMVfqFirsVfAenINO/5ykjiKsRH5xaJeWxIfUSit9zA4q+/M VSzzRa/W/LOr2tA31iyuIuLfZPOJlofbfFXxV/ziDdiD85IIqgfWrC7iAPeirLt/yLxV90Yq8L/5 zIsTc/lHFMOllqttOfk0c0P/ADNxVgP/ADjR+ffkDyp5OHlbzNdS6dcJdyzQXZheS3McwUgFoubh gwNarTpvir6e0DzT5b8w2v1rQtUtdTt9qyWkySha9m4ElT7HFU0xV2KuxV2KvmL/AJy4/Juxl0p/ zD0WBYb22ZE16GNQFmiduC3NFH94jsA57rufs7qvQv8AnFrzXd+Yvyg0/wCuSGW50iaXS2lY1YpA FeEH/VhlRfoxVmf5l+Q9O89eTNR8uXoCm5jLWlwRUw3Kbwyjv8Lfap1Wo74q+L/yU/NG7/J3zrrN prtpO9lKslnq2nwhDMt1aM3osOZQfC5dDv0YnegxVT1zXfzJ/wCcgPzAhtLSD4Yw31KwViLSxtqj nLK9Op25uRVjQAfZXFWB+dPJuu+TfMl55e1uIRX9k3FmQlo5EIqksTELyR13BoD4gGoxVI8Vdirs VdirsVdirsVdirsVdirsVTPyvIkfmbSJJDxRL23ZmPQASqScVfqDirsVfAX5tU0D/nI7VLl14C21 m2vyDXo5iua/ER15V60+jFX37iriARQ7g9Rir4D/ACHZvL3/ADkJo1pISvoX93p0ikkVLxTW4Brx /aI698VffmKvN/8AnI3SDqn5LeaIFXk8Ful2pHUfVZknY/8AARn6MVfDvkT8sfOfnuS+i8r2SX0+ noklxC08MDcZCVUr6zxqd133xVN5vyY/O3y/ci5j8tatBcw7pPYI8zr03V7UyHv2xVOdM/P38+/K Li2vNTvHVDxa21mD1mr1o0k6+vX/AGeKvSfJv/ObGofW4LfzhocBtXZVmv8ATmkRo1JoXMEhl506 kBx7Yq+sEdHRXRgyMAVYGoIO4IIxVvFWPfmLZWt95A8yWd0QLefS7xJGbooMD/F2+z1xVgv/ADi3 5Su/Ln5RWH1yMxXWrzS6o8TCjKswVIq/60MSN9OKvW8VfEX/ADmF5PTRvzLh1u3TjbeYrZZ5KCg+ s29IZafNPTY+5OKvbfKXnL8oPyn/ACd0XWLcJbNrNjDdi0jIlv726MY9QMTQnhIWUk0ROgp0xV8u +fPNnnf84fNt7rcelvN9QtWZLOzjMgtbGAs5LuBVqFiWZupOwGwxV57irsVdirsVdirsVdirsVTP zPZNY+ZdWsm2a1vbiEjbrHKy9tu2KpZirsVXwyvDMk0ZpJGwdD13U1GKv1Ms7qK7tILqI1iuI1lj NQfhdQw3G3Q4qq4q+F/+cvtKNl+cc91xoNUsLW6B234K1t2H/Lvir7S8oasNY8p6Lq/Ll+kbC2uu Xj60Kyd6/wA2Kptir4A8/n/Bv/OSN/en92lh5gi1Qj7IEc0yXlP9XhJ92Kvv/FUBr+kw6zoWpaRP T0dRtZrSWoqOM8bRtt8mxV8W/wDOJesTaD+craLd1ifVLW60+SJtgs8BE4r7j0GUfPFX3DiqG1LT dP1OxmsNRtoryyuFKT206LJG6nsysCDir8+/Pf5Ypon52yeRbbkLO71K2g09jUn6vfuhiFf2iiy8 SfEYq/QuONI41jjHFEAVVHQACgGKrsVUru0try1mtLqJZ7W4jaKeFwGR43BVlYHqGBocVVQAoAAo BsAOgGKuxV86f85s6Qk3kXQtWC1kstSNvXwS6gdm/wCGt1xV4V+Tf5AeafzKb68kyad5bt5TBcal J8bllAZo4IQasw5jdqLv1J2xV9teQfy48p+RdCXR/L9mIYWobq4ejz3DgU5zSU+I7mg6DoABir4N /PHyTbeTPzO1rRbPiNP9QXNiiEHhBcASLGQNx6fIpvvQV74qwPFXYq7FXYq7FXYqmfliya+8y6TZ Lu11e28IG3WSVV77d8VZV+fOkHSvzi82WpHHnqEl2Bv0vALkdf8AjNirAsVdirsVfpF+TWtDWvyq 8q6hy5u2mwQyvWtZbdPQkP8AwcZxVmWKvk//AJzg0UreeVdbVaiSO5spm8PTZJYx9PqPir1//nGb XBq/5L+X2LcprFJbGYVrxNvKyoP+RXA4q9RxV8S/85laAbD80LbVUH7rWNPikZv+LrdmhYfRGsf3 4q+svyt8wDzD+XPlvWOfOS70+3M7Vr++RAk2/tIrYqyjFXwh+bEE/wCXH/OR0+sQIyQJqUGt24Gw kiuGE0yj/JL+pHir7rt7iC5t4riBxLBMiyRSKaqyOKqwPgQcVVMVfLX/ADlfpcvl38w/JX5jQQlo beeGO6ZR/u2xnFzCDXbk6FwP9XFX09Y31pf2VvfWUqz2d1Gk1vOhqrxyKGRlPgQa4qr4q7FXYq7F XhX/ADmT/wCSjh/7att/yamxVhX/ADjj+cv5d+RvynuLfzDqogvxqVxLHp8ccktw6tFFxKqgIAbi QCxA98VSL8yP+cwfM2tq+meSLNtFtZSU/SEvGW+kB2HpqKxwk17cm8GGKvLfNH5TfmNpPlFfPPmW 1ktre/u0h43jMb13nV5PWlRquqkpT94QxJG3fFWCYq7FXYq7FXYq7FWe/kNpB1X84vKdqBy4ahHd kb9LMG5PT/jDir0D/nM3QGsfzMstWVaQ6vp8ZZ/Ga2donH0R+nirwLFXYq7FX2r/AM4Z+ZxqP5cX uhO1ZtCvW4J4W92DKn3yiXFXv+KvF/8AnLjy8dV/J+5vETlLot3b3wp14km3f6OM/I/LFWG/84Re YxLoXmPy47fFaXMV/ApPVbhPSkp7KYF/4LFX01ir52/5zU8sm98j6R5gjWsmj3phlPhDeLQn/kZE g+nFUZ/zhp5oGpfltd6FI9Z9BvXCJ4W93WZD9Mvq4q99xV8wf85seTDNp2h+cbdKtau2mX7Dc+nJ WW3J8FVxIPmwxV6N/wA4wedB5m/KbTYpX5X2hk6XcgnfjAAYD/yJZB8wcVes4qxz8wvIuj+efKd7 5c1YEQXSgxTqAXhmTeOVK91PbuKjvirwv8vPMv5mfk3qMXkfzlo15rflaSXhomtaZFJdGIO32Qqg kpU19M0dd+PIUGKvpcEEAjod9xQ/ccVdirsVdir5r/5zd1qOLyr5b0Tl+8u76W947dLWExVPf/j6 xVgH5S/84n33nHy9p/mXWdaXTtL1BTLBaW8RkuWjDlQWZyqJy41GzbUxV9LeQPyO/LbyKUm0XS1k 1Jf+lpeH17r5q7ALH/zzVcVSv/nJrTob78kvMYkpyt0t7iJiQKNFcxnavcrVfpxV+fmKuxV2KuxV 2KuxV77/AM4Z+Xmv/wAzbzV3WsOj6fIyv4TXLLEg+mP1MVesf85meVTqX5dWOvRJym0G8HqtSvG3 vAIn3/4yrFir4qxV2KuxV7T/AM4nedl8u/mlDp1w/Gx8xRHT3qdhcV527fMupjH+vir7rxVKPN+g Q+YvKur6DNQR6nZz2vI/smWMqrf7EmuKvib/AJxe8wzeWPzotNPvawLqiz6TdRuacZSecakfzetE qfTir7wxVjH5neVB5s/L/XvL3HlLf2ci2wPT6wn7yAn5SopxV8h/84jeb20H80/0NcMY7XzBA9o6 MeIFzDWWEkePwug92xV9x4qxv8x/J1v5y8j6x5bmoDqFuyQSN0SdKPA5/wBWVVJxV8kf84p+dLjy h+aFx5V1Wttb64TYTRSGnp6hbs3og+5POKg6swxV9t4q7FXYq7FXYq7FXYq+EP8AnK3zrH5j/NW5 sraTnY+X4l05CDVTOpL3DfMSN6Z/1MVep6J/zl9+XHl/ytpWjaXoWqy/o2zgtUSUW0SVhjVPtrLI TWhNeOKsX8zf85r+brtJIvLuh2mlK2yz3LveSgfzKAIIwfmrDFXmnmp/zv8AO2iXPmrzGup32g2I WZ7u4X0LJA7BA0EVIoj8TAH0lJ8cVedYq7FXYq7FXYq7FX2p/wA4ZeVTpv5d32vypxm168PpNT7V vZgxIf8Aka0uKvaPOXlq08z+VNW8vXe0Op2stsX68GdSEkHuj0YfLFX5malp95puo3WnXsZhvLKa S3uYj1SWJijqfkykYqhsVdiqra3Nxa3MV1byGK4gdZYZV2ZXQ8lYe4IxV+kH5TefrXz35D0vzDEQ LmaMRajENvTu4gFmWm9By+Jf8kjFWX4q+Cf+chdBvPI/543mpWA9EXU8OvabJTYSSP6jnbwuY3+j FX3H5X1+z8xeXNM12yNbXU7aK6iHcCVA3E+6k0OKpnir4G/Pjy/f/l7+d11qOm/uFmuY9d0iQCgD SSeowAB6JcI608MVfcflPzJY+ZvLOma/YGtrqdvHcRjqV5rVkPujVU+4xVNsVfFf/OWnkC68sfmB b+ctLDQ2WusJjNF8Po6jBTnQj7JkAWQHqW5eGKvp/wDJ78w7bz95B03XlZfrxX6vqsK7eneRACUU HQNs6j+VhirNcVdirsVdirsVYF+dn5mWn5feRLzVua/pa4BtdGgNCXuXU8X491iHxt8qdSMVfK3/ ADjn+SkH5latqeseZjcNoNnVHljfg9xey/FT1CCfgU8n9yvvir6Fsv8AnE38lLeTlLpdxdj+Sa8u AOn/ABU0RxVm3l78qPy28vMsmj+W7C1mT7Nx6CyTCnhLJzk/4bFXm3/OYXmiPS/ysGjK3+k6/dxQ hK0Po2zC4kb5B0jU/wCtir4fxV2KuxV2KuxVEadYXeo6hbafZxmW7vJUt7eIdWklYIij5scVfpn5 M8tW3ljynpPl62oYtMtYrbmNubooDyfN3qx+eKpzir4l/wCcvvy+bQvP0fma1ippvmNOcrAfCt7C Asq+3NOL+5LeGKvBcVdirsVe3f8AOLf5tr5N83HQtVn9Py7r7pHI7miW939mKY12VW+w5+ROy4q+ 5sVfO3/OZ3kg6l5N07zXbR8rjQ5/QvGA3+q3RChmP+RMEA/1jiq//nDXzwup+Sb3ypcyVu9BmMtq hO5tLolxTx4Tc6+HJcVfQ2KvA/8AnMHyCdc8hQeZbSPlf+XJC83EVLWc5CS7DrwcI/svLFUi/wCc MPzCW60fUfIt5L+/09mvtKVjubeVv36L/qSkP/sz4Yq+mcVYn+afkCx8++SNR8uXJCSzp6ljcEV9 G6j3ik+Vdm8VJGKvkb/nHj8xb78svzGuvLPmTlZ6XqM31HVIpTQWt5ExSOY9gA1Uc9OJ5fsjFX3L irsVdirsVSnzV5q0LyroV1rmuXS2mnWi8pJG6k/soi9Wdjsqjrir4A/NX80NR/M7zsuo6jL+j9IR xbabbtV0tLZmHJ2VKlnP25CNz0GwUYq+1vyjvvyu07ylpvl7ybrljf29qlCI54/rEsrGskksVfUD u5rQj2G1MVZ/iriQBU7AdTir4C/5yS/M2Pzz+Yc31CX1ND0VTY6aw+zIVas04/4yP9k91VcVeUYq 7FXYq7FXYq93/wCcRPy/Ov8A5gP5juo+WneW0EqEj4WvJgVhH+wAaT2IXxxV9u4q7FWD/nP+XkXn 78vtS0IKv6QC/WdKkag4XcIJj3PQPUxsfBjir86Lm2uLW4ltrmNobiB2jmicFWR0PFlYHoQRQ4qp Yq7FXYq+0P8AnF389I/MmmQ+SvMFxTzDYR8dNuJDveW0a/ZqessSjf8AmXfs2KvcfM3l+w8xeXtR 0LUF5Wep28ltNTqBIpXkv+Up3Hvir4R/KrzDqH5TfnTHDq5MENtcyaRrgFeJgd+Bk3oSiuqSjxAx V+gIIIqNwehxVQv7G01CxubC8jE1pdxPBcQt9l45FKOp9ippir8/L2DXPyU/OisfN20S7EkBO31q wl7V6fvYGKnwavhir7+0XWNP1rSbPVtNmE9hfwpcW0y9GSRQw+nfcYqjMVfLv/OXn5PGeL/lYmiw VmhVYvMMMYqWjACxXVB/IKI/+TxPYnFWTf8AOK/5zL5p8vr5R1mevmHRogLWSQ1a6s02VqnrJFsr eIo2/wAWKvfMVdirzn8zvz58g/l/BJFfXYv9bAPpaNaMrz8qbeqfswr7vv4A4q+StX1381fz/wDO kNlbwmSKIk29lFyWxsYWNGllc96dXb4m6KOi4q9xP/OFfkh/Ltratq97Dr0af6TqUfBoJJDuf9HY VCr0UBwadScVeea9/wA4V/mBaOzaNq+nanCK0Evq2kx8PgKyp/yUxVJYv+cf/wDnJnTJAmnW10ip uj2urW8SioptW4jPT2xV5x5uufzA0rWb3Q/M2oX36StGEV7bTXjXADcQwBZZJEbYjoTirGcVdirs VdirsVVLeCe4njt4I2lnmZY4okBZmdjRVUDckk7Yq/RX8lPy5i8gfl9YaIwU6lJW71aVf2rqYDmK 9xGoWMHwXFWd4q7FXYq+PP8AnLv8o20rWB5+0iD/AHG6o4j1lEG0V2dlmIHRZgNz/P7sMVfN2Kux V2Kq9jfXlheQX1jO9teWzrLb3ETFHR0NVZWG4IOKvsz8mv8AnKryzr2n22k+druPSPMMYEZv5QI7 O6psHMn2YXP7Qai+B34hVgX/ADmP5Bgi1PTfzA0sCSz1ZVtNSmioyGaNK28vIVr6kK8a9PgHjir1 /wD5xg/Mn/GP5cwWd5Lz1ry/wsbypqzwhf8ARpj/AKyLxJ7spOKvX8VeA/8AOXH5XHzF5Sj83adD z1by8jfWwo+KXTyeUn/Ilj6g/wAnnirFv+cOvzWDJN+XeqTfEvqXWgO56j7c9sPlvKv+z9sVfU+K qdzbW91by21zEs1vOjRzQyAMjo44srKdiCDQjFXwt+cP5ba/+TP5gWfmHy1LJDpElwbnQ75akwSD drWUmvKikijfbTrX4sVZ9d/85w3X1CJLTyoh1D019eeW7IhEvEc+ESx8uPKtKyVpirANW/Pb8+/z Hum0vRnuIklorafoEEiGjbfHKvqThfGsgXFWM+dfyO/M/wAo6HBr+v6WyWdwT9YkjkWd4GJ2+s+m W4c+xqR2JB2xV7r/AM43fn5+XOnaBZ+UNVtLfyzqEYVP0ioCWt44AX1Z5W3jmb9ouePgRsoVfTyO jorowZGAKsDUEHcEEYq2SAKnYDqcVfNn56/85UWOkx3HlzyFcJd6s1Y7vXEo8Ft2K253WWT/AC/s r/lH7Kr5CnnmuJpJ55GlnlYvLK5LOzsaszMdySdyTiqnirsVdirsVdir6O/5xF/KRtX1w+e9Wgrp ekuU0hHG0t6OsoB6rADt/l0p9k4q+xsVdirsVdiqA1/QdK8waLe6Lq0C3OnX8TQXMLd1YdQeoYHd SNwdxir87vza/LHV/wAu/N9xol6Gls2rLpd8RRbi2J+FvAOv2XXsfahKrC8VdirsVdiqMfWNXfTE 0p764bS45PXSwMrm3WWnH1BFXgGoaVpXFWbfkZ+Zcn5f/mBZ6rK7foi6/wBD1iMb1tpCKuB/NEwD j5Ed8VfofDNFPDHNC6yQyqHjkUgqysKhgR1BGKtyRxyxtHIoeNwVdGAKspFCCD1BxV8EfnZ+Xuq/ lN+ZcOoaGz22mTzfpHy7dr/upkcM0FT3hc036oVr1OKvsT8ovzM0z8xPJtrrlrxivV/capZA7wXK gc1/1G+0h/lPjXFWa4qkvnHyhoXm/wAu3nl/W4PXsLxOLU2eNxuksbfsujbg/wAMVfBPnn8v9b/K T8wbVNWsYdW06C4W60+S6iD2d/bxuCUkQ8h0+GRD0+RBKr7a/KPz15K84+U4b/yrDDYwx0W90mJE ja1mI3R0QKKGnwsBRh9ICrM54ILiF4J41lhlUpJE4DKysKFWU7EHFXzh+an/ADh9o+qyTap5Dnj0 m9ervpE5b6o5NSfSccmhJ/loV8OIxV4P5c/NX82fyq1i50K31EqunStBdaNdMt5aK6H4lTizBd+8 TjFUZ+ZP/OSX5i+ebL9GyzR6RpLoFubLT+aCc0o3qyMzOyHf4K8fGvXFXlOKuxV2KuxV2KuxVmX5 Uflpq/5h+b7bQrGsVsP32pXtKrb2ykBn/wBY/ZQdz7VxV+iPl3y/pXl3Q7LRNJgFvp2nxLDbRDsq 9ye7MfiY9zviqY4q7FXYq7FXYqwn83Pyt0X8xvKkuj31Ib6LlLpWoAVa3npsfdG6Ovce4BCr8+fN nlTXPKnmC80HW7c22oWTlJFNeLL+zJGxA5I43Vu4xVJ8VdirsVdirsVe7flX/wA5X+ZvJui2Xl/V dNi1rR7BfStpBI0N3HFX4U5n1EdYxso4jbauKve/LP8Azlh+T+tKiXV9Poly+3pahCwXl3/ew+tG B7sRiqdeftJ/Lz83vJlxoVnren3tw49bTLu2uIpnguVFEeiMzUPLg6+BPfFXyF+Vn5h67+T/AOY1 zDeqz2cc76d5j0+Ng4YQyFGeOh4mSJgSh77itGxV9+aTqunavplrqem3CXVhexrNa3EZqrxuKqRi qKxVjnn7yD5c89eXJ9B16D1beX4oJ1oJYJQCFliYg8WWvyI2NQcVfFOraN+Zn/OP3n6K7tpT6EjH 6rdqG+p6hbBt4pkr1p9pCeSndT0bFWea3/zm95lmhC6J5as7GXjRpLueS7FablVjW2pv0qTiryXz h+ev5qebA8Wq6/cJZyVBsbMi1gKn9llh4Fx/rlsVYFirsVdirsVdirsVdiqbeVvK2u+atdtdD0O1 a71G7bjHGvQD9p3boqKN2Y9MVfoN+UP5U6L+W/lZNJsqT6hPxl1bUeNGuJgKfMRpWiL269SSVWcY q7FXYq7FXYq7FXYq86/Oj8l9C/MrQvSl42mv2ik6XqgG6Hr6UtN2iY9R+z1HcFV8EebPKXmDynrl xomvWb2eoWx+KNx8LLUhZI26OjU2YbYqk+KuxV2KuxV2KuxV2KuxV7x/zjT+fR8magvlfzFP/wA6 rfSEwXDkkWM7n7ftC5+2Ox+L+aqr7bR0kRZI2Do4DI6moIO4IIxVvFUo81+U/L/mvQ7jRNfs0vdP uB8Ub9VYD4ZI2HxI612Yb4q+Fvz0/IrUvyz1GGeK5W+8u6hIyafcsVWdWUcjFMn8wX9tfhPsdsVe V4q7FXYq7FXYq7FXYqm/lXyrr3mrXbXQ9CtWvNRu24xxr0UftO7dFRRuzHYYq+8fyS/JHRfy00Yk lL3zLeIBqepgbU6+hByAKxKfpY7nsFVemYq7FXYq7FXYq7FXYq7FXYqwn80vyk8q/mNov1DWIvSv YQTp+qRAevbufA/tof2kOx9jQhV8Lfmd+Unm/wDLvVjZ63b87KViLHVYQTbXC9fhYj4XA+0jbj5U JVYVirsVdirsVdirsVdirsVTuy87+dLGFILLX9StYYqCOKG7njVQooOKq4ApTFUw/wCVsfmn/wBT lrn/AHErz/qpiqEufzC8/XXP6z5l1Wf1Pt+rfXL8qePJzXFUlubu6upTNdTSTynrJKxdjU16sSep xVRxV2KuxV2KuxV2Ksz/ACz/ACn83/mHq4sdDtqWsbAXupygi2t1P8zd2p0Rdz8t8VfdP5V/lD5V /LjRvqWkR+vfzhf0jqsoHrzsPl9iMH7KDp7mpxVnGKuxV2KuxV2KuxV2KuxV2KuxV2KoDXdA0bX9 Kn0nWbOK/wBOuV4zW0y8lI7HxDDqGG4PTFXyZ+bf/OIesaW0+r+QWfU9OFXfRZCDdxDrSFzQTqOy 7P2+M4q+crm1ubW4ltrqJ4LmFik0EqlHR1NCrK1CCD2OKqWKuxV2KuxV2KuxV2KuxV2KuxV2KuxV 2KuxVVtra4uriO2tonnuJmCRQxqXd2Y0Cqq1JJ8Bir6L/KX/AJxD1rVjDq3nxn0rTTR49IjI+uSj r+9bcQKfDd/9XFX1poHl7RPL2lQaTollFYadbLxhtoV4qPEnuzHqWO5O5xVMMVdirsVdirsVdirs VdirsVdirsVdirsVdirCPzE/JryB5/hJ17TgNQC8ItVtiIrtAOn7wAhwOyuGHtir5e/MD/nEDz5o ZkuvLEqeY9PWreitILxFG9DEx4SbfyNU/wAuKvDdS0vUtLvJLHUrSayvIjSW2uI2ikU/5SOAwxVC 4q7FXYq7FXYq7FXYq7FXYq7FUVpul6lql5HY6baTXt5KaRW1vG0sjH/JRAWOKvcvy/8A+cQPPmuG K68zSp5c05qMYWpNeMp7CJTwj/2bVH8uKvqD8vPyY/L7yDEp0LTVOoceMmq3NJrt6ih/eEDgD3WM KPbFWcYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FUp8x+UfK/mW0+qa/pVrqcArwW5 iWQpXujEckPupBxV4z5q/wCcNvy21MvLoV3eaBO32Y1b63bD/nnMfV/5K4q8o8wf84YfmPZFn0fU NP1eIV4oXe1mP+xkDR/8lMVef6v+QH5y6USLnynfS072irefd9WabFWK33k/zbYVF9ol/aEdfXtZ o6VNP2lHfFUrkikicxyoySL9pGBBHzBxV0cUkriOJGeRvsooJJ+QGKppY+T/ADbqBAsNEv7st9kQ Ws0ld6bcFPfbFWV6R/zj/wDnLqpUW3lS9iDd7tUs6fP6y0WKs/8AL/8Azhh+Y97xfWNQ0/SIj9pA z3Uw/wBjGqx/8lMVer+Vf+cNvy20xkl1y6vNemX7Ubt9Vtz/ALCH97/yVxV7L5c8oeV/LVr9V8v6 Va6XAQA620SRl6dC7AcnPuxJxVN8VdirsVdirsVdirsVdirsVdir/9k= + + + + 1 + False + False + + 6.944444 + 6.944444 + Inches + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + Document + application/pdf + + + DRACO_ID_mark + + + proof:pdf + uuid:719e3667-786c-f34f-8712-210d238d46b7 + uuid:0b647850-d2df-6b4b-885f-97b4d2ac81ad + Adobe PDF library 15.00 + + + + + + + + + + + + + + + + + + + + + + + + + endstream endobj 3 0 obj <> endobj 7 0 obj <>/Resources<>/Properties<>>>/Thumb 11 0 R/TrimBox[0.0 0.0 500.0 500.0]/Type/Page>> endobj 8 0 obj <>stream +Htώ&9S |5NuB0./fj4ݝ.Ό˟?|^5Jǯ+.ח?\? agݫysoz~vڮhwkڸg"\ow^ ż޼3j\p;b]c3NhƸU}tgk4~ <'*׹n~#^3K#5WK|8Vs'w2>|=^-?92>C޵'Gv&L2e3^ɓ]OP? 4I pE*K-4q̓N6;aC'M6I{&EK~(^֨+y +)r`zB3wզC WRg&AX@Vgr9Na`;]^ K AM{WC݅%v+:879vQA(,c]5 ޳ݛ0gCZav߭̋L6Ҝe`uR8J|smm6ա: *\^`cU5hA?.rܭy;l%6mw!2Xud6i=jn,!Qy¹K*<±Z89?-'#^@I7aH:TՑo y[ ]b^;|2pq&NFq!4jI\"#CdEY u!\ʒz𴺉 K-%fEQ3sݬ$vNHBBќ + - I.Ѻ6"rr5V{55ADhڵ9l7$TLȂt*9ULƊCm.* YkêYG45$ +L4 i& 5! b^1黩] 3f{bi¤fEos02.vjpр.HhP fsj8 H-/Q&MAkT) rBH{D)k,DD:(@u&ky`*E%w8[-M-axGBE.#"%lIaTR3WVse-LmM=mI8r&,T+FėFd&f} @ 8,ͷWO㱼%`ZbI#U울T3kEI%QrV]wY|6q+(HEDayzv8$ti=9d!}=I,y$5``DeIi5{'2,)0x + 2 IvjueI˻M:a,qeq+ir[N_l-AXӽ䊽da +y8-L툧 m [dG.nyOW. ]sض&O̱[o0[:W$I!}d[A}I0NBiqSM@Jwb ($<!I\v5QP +1H5ՇAp% s aI=-]jnCpib@\K,$ǾU>N. ;S;ke2a+%dW7R"j^^%Vn}E]mQ-i +zY,tm?y8洷Yn;4',e +&ޯ.Šrg!VyvfT@`Rj ٠4c#lX<Z;fImĉ[6emI0  xn8bMe%I +YM1fJM!ΚB|3_r3E"! EbƖ4=TH6[64JwZb!H+5RP 4%8 +EXúT*m" kN qR9e %)_7*9zD=uۣ6Bifi]MҊn'R6.G$l^-"CBw'.{{1M,63άDFiF|lw8o<# S_14%Ld:]JA-rv}fj)|Iw2-Z"[;/(LKBBy'"$ _3]/{N.iY ZQ|&n 3U5\H/y?3VҒLՇ/XHޕܻf$F ?n_UGX[ev*MõM2"Ҙ[٦6oB$#hVOGO8ƝRlSaH(u tt]6m$&+\JՕu^,nYM$sz"agrs(EuTU#d2RrqУ3uiJ +j++ԴK{/80 mT)ť˦ +TTiwi;6v?[2J8DI䜆56URב3&[e+ռ*^>~II[D{\D#?(,u.$;n u +]x+k<_^u'W"FY`ۆ;+R:5?}`]]ggvCfÈ^E`X jvlaqE/M<ĉ b]Ιkoڰn[.Yc0?:ٱy}`1;NAsEϒ5GMO 7a_(DZՇ<9Q G6)P K7T$$ɶw+ǡ;]4Ϋ{a郵MS=M[.ԦͲnVH1?Η;)mcY:1|{S"!?B~MEHmKd>%=xZ-7}?(V3IűYpXD2^fl-Y.нL@䳛;u3-4ZQ:T [356<5SmrtiW.vEyWWtrf"*c=uH 6$ԉ0_r |uqC]itӉ7vOiM0=- +Fp⮓N 5,(}(?XV$7ƵMΥ +%[0,J'u0^UJHmۯ+ +p:(i=gC,>9M%S +b/,U#:<\4gy^@; vQLsg;6P.x̿ݱ}̆N,AXqళ-_jԁ,嚭ni'69co+/Wz=(ꐜkztnKXXtzyOLW :j)5?W[Bp + Y8x.xsvUM܂yn n n-@?n\9F!thޝަ.˙)-"BA_yN ԘG U9)qt-?m>unE~[lվjCI$ iOҀM~S0X:1:u[coWџY+t.bmabj^I>(`銚Pl9 ^j0VǸew :Jkg +^"&luFwC5tTH~e^[ۀ!2w-[m +:dn n2*ՂXqzZt#;ܝW FEx@FڻOZW>^_@]tTh:%}kӘȔ -k 1.V$Av/qnŁ^ZKg5 Mݔ, bz%Dʚ r};- VE=%lkaα&ϾZĤɏT>-Κq:)V;1Sf$3OVzO/|.-.ɱ5Iwըq<-zS5~{/m\%]`Dvfy3 I#*Ǜ}~x)ufgGُ 7L>O_|D`[}x[ScQKxD qfG~U=րrc=Ћ^'y1wRYO~O>nߧ#r<:ֱ({tsq}֦;Q_$ƭ>-A-FRbe.[bi#PKd6)#XE_Zzg*PghE(1э5CB4G?zxze;D4Y_X⦬sfFnP*Xt->ܡk wlVS2Jƾ74Ė;nk^cKavFnADl_ƫsȡ4D B.Кʔ.XbHS˿6k +Q67tG})&QMdnSMDhb" R~qܝP0+Kk-kjC-Ru4C,P;sm[TXɅ\L+rOf7(c31.jACAqx-܊_ȫ,B(yN:Rwm H}tM'}d7;C"?'ɶF-s_ +mW!fjs +Xߋjm$h+}(,eޥMY +!/v'⋽!;ŏyXý =d؀}f ._ +(]k—xYbci]$'+c|Tu_,]&|/8 2ijeD_~|+]ݺ-݃ 7܅v/5IY6.k D" jjs /aV/F$_̈́'e|஠8.4!l9\Ulru^Hzଲ؎hu, | ['., ls|@uU{ +%20.SK +8CNBp*`&XfyD/#׼E eX!%]6<%1XD.2 +Nܪ!T"rAx`%0(GxgEoZvzCKPxJd=5xK,^}HL'Q#2,Z^nf(l^DoM[@xQ\a>ϢXB:S= M}IH&,4#ajA>F%D8 M?[^?S)^Cm=G֊կaO8zE`OE )bu|+N >r'W.OKVlu)ɚvI(A,3./Ǚ#?d7Ѥ}O0"Bg I6h>"}4@VA[@]N5dn2Ÿ7 qF(92kƼrBSh8H+Q~zUgm}K`RLv%Ov߁R ǩgW`V"@4&du+s;bQ8)`K*DP$X"ͩ=?``*j,xpG'+.E#FVY0Z(;䋨JG.‘5#oxjŤ^CfTM]| lWBY$;_4-Y%N7O/h +3AF:] :xD8 F/OnRI90+gF7ʩDI+.s[?51ؾb& ÕgSZjd#qSP,p為uF[E@l'+WXw5x:1dևR8>BLGsRGxoѴNH۴bYJK*#$8 xTBO|Lɳ*وvXUR}*;#e%HFKзkO dc-F^j8rCN<Ϣie02J@^{p|+H8#jELȐQ +7 +vݎjWރn߼MBJ;RTu&KJa={HT4#0i>[>{6LC2 |ş&0lU"# 6Ɵ*j$.#̗;g0}}88mFaBDE6nQCDHeMJÞ?qu ӛ|ɓ8;ϟb?ܜ-% 13粜JHC ̩+dAAC\BzE^Q.KMe$?BGHa . *A0 kw7` ׿}zH*QB\^A _Na8Jpg%Nn1~pIGa'Y6'r]wJ1CTIf9(j^w`aRQݴ)J*/xQ G`eR%".-@Ѻ ,Ti{ T9|BF[|RK~"J)M5R.&SS +*0/P >Tw(m7c a!Zٚ22 +.؄Z5Ȥ[,g(.!PyHiobe:v>|~8yWM $S478pK$Y3~S|ܸ/gFIN> 1(DnBw9,B~^"',ԍ<n=1vґ:i䴘!nrcZt+)Ou7.$lXXCch4+1B[چ ﯭ2ۏ~Kʌ@灹8F/7jr!|­S+(T~,kO%X?I`#(o6qLo:_!։b!(A T ?1_·gLȯQ\5P+s:;ɯS0x5,+BX頴2(mi*Lѭqb5}LFwsdETOJ8 _\m~A?wuۍޠC)t;Rz xPq6fø;5sXɍu> lu vކ1_o7JTМ K#rowIQK3vR=ZL(JiHk lΝ.$UyG KBRuYQVz\ YA\!d@+EY=Z˩p_hXuA/8T8SBgWieÂ3p{i@D@[ jիD,ފiFIK{g*cۉ.B)+/#hqyݳRPUqÕEBFK{b5^Glwn +gPzsjbmf,Wq@uQLa '{"M 퐄w%1Picb06,,@%@rAjvf ?T<"RQQ0Ow%{OVw{"Ȳ|DgeV/"'U4͆`*=8Öe˖b?+5w(3;Cj~ob%no=̙'t#)6^1dAcqOfL0Oɓ;^ZIH DsDb!a 8Px><=n\_{fFuQn6&5Hܹơa3}JpqyQ.%oXU 漬N\=3y ?xr EZԎ xԗxg32a#-bo3:UDe~'cKb+)H +.3;27F[I7v[L-Ē>n!LSʝR>pwƪ 5[V^+ջWW 0";\_)Q|q +bdSfd!++nQ?-SܭNC%DW-M xJ,fn'J뱊ϑ| HZq1~. \)1K(6'ԟϫwJ +$|BfF^jy56س܄dƔCaWU'.kn*M?isL8?"ygٟzTa[4%QS婹f$H$K=na`گdݚ qV%<"KSvf9y$gگ!;:MQÙoҾ8dH~uݠJy%VW4n/4o>ݣaqthz#r9*[X hA( 8.H$ ΍aVK*T*>5|&Nm_'5WKFC-lҢtO6P<>nVt_u;仡[u,W) w-%&-,V<iGz9p{)+B,;M`l='ņ48sVJV=FhcQIA8lj0 ap+P2 +ˁVlvWGc .Ce\ܪ(c&M-RLF,״<OͪxG c= +cǩNIh^}i,u8KJw/nk]$K`oouo + H$@P0@΄C$B!@ eį@s + od^ނ8&u)c!.\pudY"Qpޫ >imv'$֍5::DUb{8B LZZz1&o(LE@CQ[KbHƛ D\Z9 CĐp8 p.yh77"x,3(8V]u;~ln|_py`A1u>%%+_z S޺Qb;2re(YΉq=uQe<I6 `,;pQ)C~DEV Xe@r8 +̨VDΉN2j+=pE1EAfJ"̸}5]-G{#Aṇl?wXKceQO5 +UXAL|mɼ186AuJbP&N댝q x"9}57.hVT/=$J݂!#gsUqVtq& XJw(j\ON)Y_}y#jӕsc kL fƣVG)2JΟ + ndž5+VUJWCڑ'ޑ j'>~s(o'vi{ƿ 5wŒ?q&cE߬))fЁX7A6q\wwZMPHxtnRk5NO&S_G{~Ӛ?aK̬Ь_!<ሬH>OzJ9Ai*&w'@oqT|MތߘQLg^ېOo,3|f"]0}f]78c~Ԥ_=$x2E;BKTzVw{)@υ4FH ZgŎ3)Ќt[lZp*3Lu0m({^JC Ck%=\ q_%=QQT l +ߘF)>TN=v1Hw7$}a&]G^ɌN5-s]ὕIeEֈNmϻ3nBڅsV7'T^x{ +~ +ْ}3Nj+Q]#Sv.S-KQx,>ǕȺVd,[R{IfɽN#O(_b)8ݓQ`fx(˘2S7[V[F}>S)#B̑cs.D6 +ɭtn E'"Zn0%ޤ||JC uJgu>4uQشwK68@W8O":9ڪI+ÌN~^Hʆ<2?aaᘳ!oƕ&!FA#=@Lv:W%F UG=C/ +M G6!rZdp+2Ξ,BZM}i}knTqJw3TȘPAbRVR/GʔQ! +wW hEd3oigI#m֣20( %`~c;`;ghrizU-,?b| wi[".S=P9Y~2О%mEUK$[6f-?C+/)u f>wKGEjf @#ٞ<s\(+>g,eһK>W!}WtOm4rMq6D =3Ry)w~O- Tc2>ʊ#Tx_ C=o+|eߩk+^9zFnk?ah.YaJ }0~3iliQO;EW^;$jq1㼒AOX?m +E@t {K٫2OS]\A~|R_ iavU[|kAEX {6YÂY yu zA]iiB-vV\%G) [$ݚζ*Wmϑio;{d\ƨQvtJ zɉ>( s5JAN~Ox(2lo;61w%tW^Ua1R֔ŎCUW\vyW36a\J "o]dbj_=Hyd]8v@dl8t3p$mNwuU KS#b;jU;7uHu* qbOp`Ne?QEMDf4mPJEed.,kF-()ԸY!~X soADsCBu7R%R$4Y}r o9W =0@b6Sio`7[lt)/ÎJD'4ffv5Qz肔 l^Mm x|&WE4O"% 3+շPUEJsW<l nT'.em˺Iqpd3D3ʄpd߀fpYP Oo4J]6ۄLA<*nǰPEn'(=/s洳@J:5J1C"Q3Z/w;5L*'z8B kAX68^-:Bwŀ;O:4 x9ynA'SLV $Y8u`R+qɦrԹֻiyP$gr뉹޴Sߵ Gwz&O"Ta?XGMdR!:TzylmVS\-rI۵UO]bqC$í,\_92=eb5CevCK1dvuc=O;_ElD㑈~F$w~ʏ}ӊ~O]ޱd$n1on%UE3I"O{d!pnJy[S'GFwLɛxk4b冶-m,7<<г!tVg_[r8WCB?!^ipm6H t!#R\ NХ޺euTO\ן; "{ ;ʯ\ow`Abc٨R麆Xq!y'#^23tD cūvT6Z? Bkf #>$6@x +To`"JiE[yZx7dL'L^@)#*b!?uqyeP. ٺ8o|׫W^|*1:??A4%W.3 <_>'XcU:w_> +$]Q+WSWRUϯc;TL>ul2" ̛:KיNIޟ>stream +8;Z]`>HYgs$j=rDItQSf&h'_$1ObQ1KUT);lB?5D_A.@I^T;S/(Nb$kTEC6ldrX=6 +.5#jRF7'Bjg_L@J?,`mje+<5e*)n78%7ZNGpRaKMG=)(Vj`gc1M[S:ko%s&RBm">b +U:&*rOFi9L82jf +h.iQq4#WqAmjQW-kcFB#j3**/f6X:4Pk;<"a@`PjCD=M/AK!dQNB;Hcgg0(>7R,"P +S+'faD2*87$gd;>ju0U/i=(P@IiF\K0RbJ)\A]+U`mh=@06$>pb^%5ahmMBm&Ui4@ +YL`b/f endstream endobj 12 0 obj [/Indexed/DeviceRGB 255 13 0 R] endobj 13 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <> endobj 14 0 obj [/View/Design] endobj 15 0 obj <>>> endobj 10 0 obj <> endobj 9 0 obj <> endobj 16 0 obj <> endobj 17 0 obj <>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 17.0 %%AI8_CreatorVersion: 20.1.0 %%For: (Abby Lindstrom) () %%Title: (DRACO_ID_mark.svg) %%CreationDate: 10/31/16 10:57 AM %%Canvassize: 16383 %%BoundingBox: 60 60 440 440 %%HiResBoundingBox: 60.2979633274945 60.3760065136557 439.703031687162 439.624020110948 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 13.0 %AI12_BuildNumber: 174 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%RGBProcessColor: 0 0 0 ([Registration]) %AI3_Cropmarks: 0 0 500 500 %AI3_TemplateBox: 250.5 249.5 250.5 249.5 %AI3_TileBox: -40 -130 540 630 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 0 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI17_Begin_Content_if_version_gt:17 1 %AI9_OpenToView: -520 754 1 1928 1104 26 0 0 -4 37 0 0 0 1 1 0 1 1 0 1 %AI17_Alternate_Content %AI9_OpenToView: -520 754 1 1928 1104 26 0 0 -4 37 0 0 0 1 1 0 1 1 0 1 %AI17_End_Versioned_Content %AI5_OpenViewLayers: 7 %%PageOrigin:-55 -147 %AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 18 0 obj <>stream +%%BoundingBox: 60 60 440 440 %%HiResBoundingBox: 60.2979633274945 60.3760065136557 439.703031687162 439.624020110948 %AI7_Thumbnail: 128 128 8 %%BeginData: 10786 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FD35FFA87D52522727F827FD07F8272752527D7DA8A8FD64FFA87D %5227FD19F85252A8A8FD5CFF7D52FD21F827277DA8FD56FF7D52FD28F827 %7DA8FD50FFA852FD2DF82752A8FD4CFF7D27FD32F8277DFD48FF7D27FD37 %F87DFD44FF7DFD3BF8277DFD40FF7D27FD3EF827A8FD3DFF27FD42F852A8 %FD39FF7DFD45F8277DFD36FFA852FD48F827FD34FF7D27FD4BF8A8FD31FF %52FD4EF87DFD2FFF27FD50F852FD2DFF27FD52F827A8FD2AFFFD1FF82727 %527DFFA8FD30F827A8FD27FFA8FD1DF827527DA8FD04FF52FD32F87DFD25 %FFA8FD1BF82752A8FD07FF7DFD0EF8277D5227FD22F8A8FD23FFA8FD1AF8 %277DA8FD09FFFD10F827FFFFA827FD21F87DFD22FFFD19F852A8FD0BFF52 %FD0AF85227FD05F827FFFFFFA852FD1FF827A8FD20FFFD18F827A8FD0CFF %A8FD0BF8A827FD06F852FD04FF7DFD1FF827A8FD1EFF27FD16F8277DFD0E %FF52FD0AF852FFFD09F82752A8FFA8FD1FF827FD1DFF27FD16F852FD0FFF %A8FD0BF87DFF27FD08F8275252A8FFA8FD1FF852FD1BFF52FD16F8A8FD10 %FF52FD0BF87DFF7DFD04F8277DA8FD07FFA8FD1FF87DFD19FF7DFD15F827 %FD11FFA8FD0CF8A8FFFF52F827A8FD0BFF7DFD1FF8A8FD18FF27FD14F852 %FD12FF52FD0CF852FFFFFF7DFD0EFFA8FD1FF8FD17FF52FD14F87DFD08FF %A82752FD08FFFD0DF827FD14FF52FD1DF827FD15FFA8FD14F87DFD08FFA8 %F8F87DFD07FF52FD0EF8FD15FFA852FD1CF87DFD14FFFD14F87DFD08FFA8 %F8F8F8FD08FF27FD0EF852FD16FFA852FD1BF8A8FD12FF52FD13F87DFD09 %FF52F8F852FD07FFA8FD0FF827FD18FFA827FD19F852FD11FF7DFD13F87D %FD0AFF27F8F87DFD07FF27FD10F8A8FD18FF7DFD1AF8A8FD10FF27FD12F8 %52FD0BFFF8F8F8FD08FF27FD09F8277D7D527D7DFD19FFA852FD1AF827FD %0FFF7DFD12F827FD0BFF7DF8F852FD07FFA8FD0BF87DFD0EFFA852F8F8F8 %7DA8FD05FFA87DA8FF52FD1BF87DFD0EFFFD13F8FD0CFF52F8F852FD07FF %52FD0CF8FD0FFFA87D27F8F8277DFD05FF2752FFFFFD1BF827FD0DFF52FD %12F8A8FD0CFFF8F8F8A8FD07FF27FD0CF827FD11FF52F8F8F827A8FFFFA8 %2727FFFFA8FD1BF87DFD0CFF27FD11F87DFD0CFFA8F8F827FD07FFA8FD0E %F87DFD11FF27FD04F82727F8F8A8FFFFFF7DFD1BF8FD0BFF7DFD11F827FD %0DFF7DF8F827FD07FF52FD0FF87DFD10FF52FD07F87DFD05FF7DFD1AF87D %FD0AFF27FD11F8A8FD0DFF52F8F87DFD07FF52FD0BF87D7DF8F8F852FD0F %FFA8FD04F8277DFD08FFA8FD19F827FD09FF7DFD11F852FD0EFF27F8F87D %FD07FFFD0CF87DFF52FD04F8527DFD0DFF7D5252A8FD0BFFA8FD19F8A8FD %08FF52FD11F8FD0FFFF8F8F8FD07FFA8FD0CF8A8FFFF7DFD05F8A8FD1DFF %27FD17F852FD08FFFD11F87DFD06FFA8FD07FFA8F8F827FD07FF7DFD0CF8 %A8FFA827FD04F827FD1FFF52FD17F8A8FD06FF7DFD10F827A8FD05FF527D %FD07FFA8F8F852FD07FF52FD0CF8FFFFFF27F8F8277DFD21FFA827FD15F8 %7DFD06FF52FD10F852FD05FF7DF8A8FD07FF52F8F87DFD07FF52FD0CF8A8 %FFFFFFF8F8F87DFD23FFA87D5227FD11F827FD06FFFD11F8FD06FF52F8FD %08FF52F8F87DFD07FF27FD0CF8FD04FFA8F8F8F87DFD1EFFA8FFA8FFA8FF %FFFF7DFD11F8A8FD04FF7DFD10F852FD05FFA8F827FD08FF27F8F8A8FD06 %FFA8FD0DF8A8FD04FF52F8F8F852A8FD1BFFA8522727F8F827FFFFFFFD11 %F87DFD04FF52FD10F8A8FD05FF27F827FD08FF27F8F8A8FD06FFA8FD0DF8 %A8FD05FF7DFD04F852A8FD1BFFA87DFF7DF87DFF7DFD11F852FD04FFFD10 %F827FD05FFA8F8F852FD08FFF8F8F8FD07FF7DFD0DF852FD05FF7DFD05F8 %27FD09FFA8A87DFD05FF7DFD07FFA827F8F8F8FF2752FFFFFD11F827FFFF %FFA8FD10F87DFD05FF7DF8F852FD07FFA827F827FD07FF7DFD0DF852FD05 %FF52FD04F852FD07FFA852FD05F82752FFFF52F87DFD06FF522727277D7D %7DFFFF52FD11F8A8FFFF7DFD10F8A8FD05FF52F8F87DFD07FFA8F8F827FD %07FF52FD0EF8FD06FF7DFD04F827A8A8FFA87D27FD0AF852A8A8F8F87DFD %05FFA8FFFFFFA8FFFFFF27FD11F852FFFF52FD0FF827FD06FF7DF8F87DFD %07FFA8F8F852FD07FF7DFD0EF87DFD07FFA87DF8F8F827F8F8F827FD0CF8 %52FF7DF8F8A8FD0BFF52FD11F852FFFF27FD0FF852FD06FF52F8F87DFD07 %FFA8F8F827FD07FF27FD0EF827FD0AFF7D27FD04F87D7DFD0DF87DA852F8 %F852FD09FF27FD12F8FFFFFD10F87DFD06FF52F8F87DFD07FF7DF8F852FD %07FF52FD0FF8A8FD0BFF7DF8F8F8277DFF27FD0CF827A8FF27F8F87DA8FD %06FF27FD11F827A87DFD10F8FD07FF52F8F8A8FD07FF7DF8F852FD07FF27 %F8F8A827FD0CF8FD0DFF27F8F8F85227FD0EF827A8A852F8F8F852527D52 %27FD13F8A87DFD0FF852FD07FF52F8F87DFD07FF7DF8F87DFD07FF52F827 %FFFF7D27FD0AF852FD0DFF52FD05F82752FD0DF87DFFFF5227FD18F87D52 %FD0FF852FD07FF27F8F8A8FD07FF7DF8F852FD07FF27F8F8FFFFFFA87DFD %0AF827FD04527DA8FD07FF7DF8F8F827FFFF7DFD0EF8527D27FD18F85252 %FD0FF87DFD07FF52F8F87DFD07FF7DF8F87DFD07FF52F827FD06FF7D52FD %0EF827A8FD06FF7DF8F8F87DFFA8FD29F85227FD0FF87DFD07FF27F8F8A8 %FD07FF7DF8F852FD07FF52F8F8FD09FF7D522727FD0BF852FD06FF52F8F8 %F85227FD29F82727FD0FF8FD08FF52F8F8A8FD07FF7DF8F87DFD07FF52F8 %F8A8FD0FFFFD04A85227F8F8F827FD06FF52FD05F827A8FD26F827FD0FF8 %27A8FD07FF52F8F8A8FD07FF7DF8F827FD07FF52F8F8A8FD15FF7DF8F8F8 %27FD06FFFD04F827FFFFA8FD25F827FD0FF827FD08FF52F8F87DFD07FF7D %F8F852FD07FF7DF8F87DFD17FFF8F8F87DFD05FFA8F8F8F8FFFFFFA827FD %34F827FD08FF52F8F87DFD07FFA8F8F827FD07FF52F8F8A8FD17FFA8F8F8 %F8FD06FF52F8F852FF7DFD36F827FD08FF7DF8F852FD07FFA8F8F852FD07 %FFA8F8F827A8FD17FF7DF8F87DFD05FFA827F82752F8F8F82752FD32F827 %FD08FF52F8F852FD07FFA8F8F827FD07FF7DFD04F82727A8A8FD14FF27F8 %7DFD06FF52FD05F827FFA827FD31F827FD08FFA8F8F852FD07FFA827F827 %FD08FFFD07F827277DA8FD11FF52F87DFD07FFFD04F852FFFFFF7DFD31F8 %27FD08FF7DF8F852FD08FFF8F8F8FD08FF27FD0BF82752A8A8FD0CFF7DF8 %A8FD07FF52F8F852FFFFFF7D27FD31F827FD08FFA8F8F827FD08FF27F8F8 %A8FD07FF27F8F827FD0BF8277DFD0BFF7DF8A8FD07FF7DF8F87DFFFF7DFD %33F827FD08FFA8F8F827FD08FF27F8F8A8FD07FF52F8F87DFFA8A87D7D27 %27FD06F8A8FD0AFF7D52FD08FFA8F8F827FF27F8F8F85252FD20F827FD0E %F827FD09FFF8F8F8FD08FF7DF8F87DFD07FF7DF8F8A8FD08FF7DFD04F8FD %0BFFA8FD0AFF27FD06F852FFFF27FD1FF827FD0EF827FD09FF27F8F8A8FD %07FF7DF8F852FD07FFA8F8F852FD09FF52F8F827FD16FF27FD04F8277DFF %FFFF52FD1EF82752FD0FF8FD09FF52F8F8A8FD07FFA8F8F827FD07FFA827 %F827FD0AFFF8F827FD16FF7DF8F8F852A8FD05FFFD1EF82727FD0FF87DFD %08FF7DF8F852FD07FFA8F8F827A8FD07FF27F8F8FD0AFF27F852FD16FF7D %F8F87DFD07FF27FD1DF8527DFD0FF8A8FD08FF7DF8F852FD08FF27F8F8FD %08FF7DF8F87DFD09FF52F852FD16FF7DF8F87DFD05FFA852FD1EF8527DFD %0FF852FD08FFA8F8F827FD08FF52F8F87DFD07FF7DF8F852FD09FF7DF852 %FD16FF7DF8F87DFD04FF52FD20F87DA8FD0FF852FD08FFA827F8F8A8FD07 %FF52F8F852FD08FFF8F827FD09FFA8F827FD16FF7DF8F87DFFA852FD04F8 %2752FD1CF8A8A8FD10F8FD09FF27F8F8A8FD07FFA8F8F827FD08FF52F8F8 %A8FD09FF27F87DFD15FF7DF8F82727FD05F852FF7DFD1CF8FFFF27FD0FF8 %A8FD08FF7DF8F852FD08FF27F8F8A8FD07FF7DF8F87DFD0AFFF827A8FD14 %FF7DFD07F87DFFFFFFA8FD1BF827FFFF52FD0FF87DFD08FF7DF8F852FD08 %FF27F8F87DFD08FFF8F827FD0AFF7DF827A8FD13FF52FD04F8527DFD05FF %A827FD1AF827FFFF7DFD0FF852FD08FFA8F8F8F8FD08FF7DF8F852FD08FF %52F8F8A8FD0AFF7DF8F87DFD12FF27F8277DFD09FF27FD1AF87DFFFFA8FD %0FF827FD09FF27F8F8A8FD07FF7DF8F827FD08FF7DF8F852FD0BFFA82752 %A8FD11FFF8F827FD0AFF27FD1AF8A8FFFFFF27FD0FF8A8FD08FF52F8F87D %FD08FFF8F8F8A8FD08FFF8F8F8FD1FFF7DF8F87DFD08FF7D27FD1BF8FD04 %FF52FD0FF852FD08FF7DF8F827FD08FF52F8F852FD08FF52F8F87DFD1EFF %52F8F8A8FFFFFFA8A87D27FD1DF852FD04FF7DFD0FF827FD08FFA8F8F827 %FD08FF7DF8F827FD08FFA8F8F827FD1EFFF8F8F85252522727FD20F87DFD %04FFA8FD10F87DFD08FF27F8F87DFD08FFF8F8F8A8FD08FF27F8F8A8FD1C %FF7DFD0CF87DA827FD19F8A8FD05FF27FD0FF827FD08FF7DF8F852FD08FF %52F8F852FD08FFA8F8F827FD1CFF27FD05F827F827527DA8FFFFFFFD19F8 %52FD06FF7DFD10F87DFD07FFA8F8F827FD08FF7DF8F827FD09FF27F8F87D %FD1AFF7DF8F827A87DA8A8FD07FFA8FD19F87DFD06FFA827FD0FF852FD08 %FF27F8F8A8FD08FF27F8F8A8FD08FF7DF8F827FD1AFFF8F8F8A8FD0BFF7D %FD19F8FD08FF27FD10F8A8FD07FF7DF8F827FD08FF7DF8F827FD09FF27F8 %F87DFD18FF52F8F852FD0CFF27FD18F852FD08FFA8FD10F827FD07FFA8F8 %F827FD08FFA8F8F8F8A8FD08FFA8F8F827FD17FF7DF8F827A8FD0BFFA8FD %19F87DFD09FF27FD10F87DFD07FF27F8F87DFD08FF27F8F852FD09FF52F8 %F852FD15FFA8F8F8F87DFD0CFF52FD18F827FD0AFF7DFD10F827FD07FF7D %F8F827FD08FFA8F8F8F8FD09FFA8F8F8F8A8FD14FF27F8F827FD0CFFA8FD %19F87DFD0BFFFD11F852FD06FFA8F8F8F8A8FD08FF27F8F852FD09FF52F8 %F827FD12FFA827FD04F8277D7DFD09FF27FD18F827A8FD0BFFA8FD11F87D %FD06FF52F8F87DFD08FF7DF8F827FD0AFF27F8F87DFD10FFA827FD09F827 %27525252275227FD19F87DFD0DFF27FD11F8A8FD05FFA8F8F8F8FD09FF27 %F8F87DFD09FFA8F8F8F8A8FD0EFF7DF8F8F827A85227FD25F8FD0EFF7DFD %11F827FD06FF27F8F87DFD08FF7DF8F8F8FD0AFF52F8F827FD0DFF27F8F8 %F827FD05FF7D7D2727F8F8F827FD1BF87DFD0FFF27FD11F827FD05FF7DF8 %F827A8FD08FF27F8F852FD0AFF27F8F852FD09FFA87DFD04F852FD0BFFA8 %FF7DFD1AF827FD10FFA8FD12F827FD05FF27F8F8A8FD08FF7DF8F827A8FD %09FFA8F8F8F87DFD06FFA85227F8F8F827A8FD0EFF27FD1AF87DFD11FF52 %FD12F827FD04FF7DF8F8F8FD09FF27F8F852FD0AFF52F8F8F8A8FFA8A852 %27FD06F827FD0DFFA827FD1AF827FD12FFA827FD12F827FD04FF27F8F87D %FD08FFA8F8F8F8A8FD0AFF52F8F8272727FD05F82727F8F8F827A8FD0AFF %7DFD1CF8FD14FF7DFD14F852A8FF52F8F827FD09FF52F8F8F8FD0BFFFD08 %F8277DA8FF7DFD04F852A8FD07FF52FD1CF87DFD15FF52FD15F85252F8F8 %F87DFD08FFA827F8F852FD0BFFFD04F852A8A8FD05FFA827F8F8F82752FD %04FFA827FD1CF852FD17FFFD1BF8FD09FF7DF8F8F8A8FD0AFFA8F8F8F852 %FD09FF7DFD05F8527D52FD1DF827A8FD17FFA8FD1AF852FD09FF27F8F827 %FD0BFFA8F8F8F87DFD0AFF5227FD22F87DFD19FF7DFD1AF8A8FD08FFA8F8 %F8F87DFD0BFF7DF8F8F852FD0AFF52FD21F852FD1BFF52FD19F852FD09FF %7DF8F8F8A8FD0BFFA8F8F8F852FD06FFA87D2727FD20F827FD1DFF27FD19 %F852A8FD08FF27F8F8F8FD0CFF7DF8F8F852A8FF7D5227FD23F827FD1FFF %27FD1AF827527DFD06FF27F8F827FD0CFFA8F8F8F827FD27F8FD20FFA8FD %1EF827527D7DFF52F8F8F852FD0CFFA8FD29F8A8FD21FFA827FD21F827FD %04F87DFD0DFF27FD26F8A8FD23FFA827FD26F8A8FD0DFF27FD24F8A8FD25 %FFA827FD25F827A8FD0DFF52FD22F8A8FD27FFA827FD25F827A8FD0DFF27 %FD20F8A8FD2AFF27FD25F8275252527D527D527D52522752FD20F827FD2D %FF52FD50F827FD2FFF7DFD4EF87DFD31FFA8FD4BF8277DFD34FF52FD48F8 %52FD37FF7DFD46F87DFD3AFF52FD42F852FD3DFFA827FD3EF8277DFD40FF %7D27FD3AF8277DFD44FF7DFD37F8277DFD48FF7D52FD32F827A8FD4CFFA8 %52FD2EF852A8FD51FFA85227FD27F8527DFD56FFA87D5227FD21F8527DFD %5DFFA87D522727FD17F827527DA8FD64FFA8A87D7D52522727FD07F827F8 %272752527DA8FD34FFFF %%EndData endstream endobj 19 0 obj <>stream +%AI12_CompressedDataxܽgC*((@`FsYVH|UաD{9@wQaʡ*8j#+x,,A'Oְ?e:Ϋ97movګqe*Tv~NSixutY(޾+\92tU E>+aUVlQiUQNgخ7;V +$/o^69AWuEU%q̋ #IS9yESyE A9]ҠR6nN;N/'xS?4ZVof ⼈*ΰ٪ JX|#]/?c\5X ka?Gl%mtt}Lȿu8 2イ_BZeY^N"il?nlG7Vwn +:IhA{VoוGci /5sqO7ƫo;6tߚ1XUL;6ם[,pqU`L^82Ukb4zm9lm jl!d2`_9L:5YYmTc{fF1Ukraz.Q/ QPn` o,V^|##I:,t;{6;%o^:AW'Y#NKkY7F&\Mvy>ݝO'Q VUGWR&;؆r%j7ץ/stW2v*J7 +l!6l #dp>[ڀyadB7jWBWZ͏^٬wzgiY}{aߑW[Cy|e d߬T[(}ȤM˫ {xگ62H,*:ts/bi&~Y΋EU &/?͏(Tf2c\ɜE [3ՍvBVO$/X3:?QV?*6;N2 Ǎ_/^uZ!HJԥiO9ៈ]Lc|cc/QgO=i< 9^ OFd!;D3êhD^ gj3xY=L(*N qPPy +&EJ\NFdxS6S_J; yjX7N{пD>t3ʃ/kr_^c Miha.ϩZMau2aSE2" +!7؟Z.t<MDSjzϲ<ݱZ'{hV`wvztK}ksdMc05],X- q7ԓN{yٯ1nd聩5$ßu+5Ks>2;e)haeH+LP1:}gKbBl@,$_\*WjBFxMe L }٪ώnw Ll5lL]ӱ6T-(emy٬}Sb5`?X.H; +gS|Z]3w(UL .2 vaq}vf07!f f62OGEF~sF;0Vz:iԛ︝2jJzYNeg1&8ԨOOK_%gF3ٙgATߤL6{uGpdwC!+:BN5zӫ73? M~p 3Ճ(m7i`/KɬQ{~e+O0;ᴇ-2i>+S* e6Qq´ +w4g̭ֈQnk`6vsrQQcZZ /G;U#tt9 rЀE5lWFW1 ۜ${$պ^q ^s-ء\:~zpl ^=ׯu[?mb!zL訵v?`f;}Vz @y2=}s"K DO^2XLUh=@IJ`GyzblА +.MTirXť*ܧ0>J'2)t hDBq<_As}vzc/'o;n?<'2}8ai*nM\K1ӍbJdPԣ~6.N%eQ2]O?![p~uځm103a̸FY'&5\)Dg[ sn9+<9e I< =vaIi0XATz'^kU 4Vr+`Qeڍ-ܢ2P+L#S%5 ~м29f+NҦF`期^} 1 9C +9N+~͈t/vnkުZg(vFdt^?|=p-f^}K8f6`<8j3 +O3PPȒ~ ۵yN> bF >-txl=;;NB$Lj~ocLU*Ci_iV^]6 "&*|r@Cp l~4 fc֦b#3Bp`yIX>?L)bhDn. !=Ft8F}4F1*Pp2>$xHA;6ݱchfy&A%_Aƻ ޤy, Fl7M9">n)z +T~x1^Mȏf4_ٱUZ5]VB#F\l}oTwdDX;4w]il &cgvAḠSs?9EbI4á_|hqTm(31XjM+98g-5q"y$_tqj'Ge.l'1ʞ:]00#C{HDvx"*|-b2 97b5Muk<:d1u10 07I!8Z6)1Q5Pu=e\_"]D^X;{@N1X];P3Ç3-+S;!V3rl6h\c}dTgX tϊ.Mm6|cxb_D8 \ *z1"q=[U"܈냠u! ޱ"`A{k M隚sߒ`c?xtXqHl_Ȼ*m8s ]_gg:x0+4֠J}T"k:Z`O۰]&*V&L6Qt~]"^/:ZPdo$znH̱Q%/ec÷\TՎ94uE CnN.T+ZvjW܉#M>;7U yL::A>CD<3~G|b9FC_en^t~6`eJ rhm߉حZ@ #]o0ssx= .1NJ}w˳N#ɕT{o/J:0M96Wq;HObN')\4@f6w5u[sI69 _֋ y&n]vJˍJi2g"-o$X2ZOOg^%2ի})N."ˉbB \K:{w4QS{މ\~5dQ-tO~+w#Wz,?\7 +5~QąA"eDUil7VW+4qiivi%.'[$ Qt>L&8sIʉ0XXR>W^/>nt'~yeO@y rAcIװ3XU.+YkPvu_ғ/AK נ{n!U]|&}aֺϠKTzx;^ƒrw5y>) ZVo +KcʖևlE4[3tq;V<<2~C(5aծ{OAy^~ĝ,Aa:WkKG+)]`ϵ7N)Ao^}^G1nރɛ9AoD{:*yzz9ׁkP21^Y^g&zv^*m~zf/]t +RJ7*]D~<,AԾsj]4obEYaa :ʸVA<NFl&pr5hfmNnGYǠJW:}' # +6˹+4:&&Wc zswxQyS\څY߻>\߷~o?Qz58?Ңϯa3ŤwCuU4͜wKsmǒg߷|duAL/5_g[ٯ5b\kmqOZ]}dkܪmmBm)cjo|siu~;䫺߃ۯ[a߯akCAڼ}[kW!X+'VJEsN_@m0)1ƫ\|7',mg i'Y 9/"~ScL3'Z{ !d0w`_xF5 mn͝Yfօ An뉕(n}+:Ԡ5uvPjT;ݹb/.ۃ?]Y~2k9M? +5qb;Xk]FgЇΕC;JlAvt=bd%_wPG{'cA*>ֿ[vvh;eu0>-O ~k~.dMoy#rmdg_>WP7.?6dS VeGMnr1 +9=XF6qx6JIϥӲ0\^gV.p˜9|]DcnlB.G $(y6/kJ1Ɋ]x@91.uOɽB$" ݿ+^wpZ߲P?ģ _Dž2Bb3~yw9(ȾԘ Xtȃj8!8i%<z61>u׹⤻|cu ^٬?LO(>dTɲmo$<ϥ=ڍq&n^eh}3R&ʪEcG}rۙzAh +3saӋ06t~G1&lca2qyØwueau椻Q_){Q(KwaN+7 +y2bDF8cjwC?{7*e.I13 <絹W{-0osM~D ؒ|e\,|qK*%+ P0ow"N %"kO='vE][Lju3Kc6>Sb}tR*uO_p#EؿvBGl(;w= 20;j +):{6bƃX^7z3&XבF RlxS҇&6T9ؚU,D0a⏎Bk608%t6XɶN3(0&D@,&NrPb?]aGj~Ʌ*-eҠ侴{^ΆO4`v Fqj0TqQ<ư4fGf/d`p0pa +7|qa.wK`i3Fmrg]D"d$.._y'IHsx|<$smp'Q}}=$ҖYpj7áS,NY S<&\ɇ#Ru!\`b X޺%BG8< NUz{HXe 31\>Ui?zՋdll1h-u.cDr--X2"W:1sGn7тN d[7Iy|Ȃ6vOl,AtY V-*xvY|]f6->U_CI;CgbW7.OFpa3;7_I/ifwL؏zB5؀~Tؽ?."E*`%7$՗rhDW/n&y=^#}}s5Mbz'0Ջ_ +gԤd6oJ,ȑ?$ a}4g`ʉEK,+,ű(.iK]%O,&H? )FZ^de' pDRU4|qq_|j*bz >KC^SX._꾏DݡlۀX$7.a's^T,ݸ >ya허xk}Lez$@7 +oќExpuU# j2Hp*6?ģV!;?uG&dn㤂$tqUYi 0fH,m[Ѧ:јMU hZ:"9  +D4Ae=@θcg{[i>- ۯ`XRuva_>,jN/!(r` +l=svz(:jg'T\N':~nvr=zǿ/ծ XaՙAf֠b7jںՐ-񥂊o +;e~G>V=<՝}Uu5;n|*A>1 mqoЋTr5' <_}kz(F9micC5 b5w}S]sgKEw˔/?yk\x_t7㚻&|ƺΔݹGE={4gNܺN2qQʢXD{4MɰԅtcZBɊ\Uɩ+`R8ƯJûVSaH"#&Z=%wEh)޳w_&, # +:) +:_N8L*ǽc1w?SԒ^ -#D5=hҼ'qW roU{VbWG}emfi7s:"(YCC=WQk&?]4*D.eΎ"Ƹ^GgU>F-dc\e䂔x;;='s)= c2dwlupgO3, oqz"'Ñ)o [:<2;zI!'|n ˺XX{=LԾͬ} E%=duKn+O T-Gk&o(_߾Z!Ք2#/ޏUsV* WS׃n®ޜE=;B~K'dWG-c +*bzY2x51jDR*5bw_17} Jmv5K^0T\=GոsyN,9ҙ_H/FLi " {4<@ * oץ/?+7J[{FO{紶\6JT. 1 tQן}8g]U{VOz8.ɿ 7|_}ܲ_2^_XY_p8W?޸%߼-Pv.k-өOiZ:ƹdZ>Z?TOJwzA/TwVt J.,=tw|b}2J0yW; +іb#Z bV p,O`'r *EMpFpiӈģ1STkcNnZ?[qFKB12NW! hѫ"VEJ ьOfWl+$7.biYLj$Ok)*XyZASO@/,-c67M沓]Nc6W B0̗;}C6$03p/z"dK<ˁgEF860Z-^\hGIqX;fr ty6r<3ϏwzXJy?CN3r— 4r!})ggD8J6TַGdv`sۂNF;&埬DfT)(ĥ^Ѯ[f: 8t^vE*v6zWNYX-8 \X<}!6R.k̎u#_&ZʱG]Ǯ (<. 䐪hD1K(9/sݗ/]s?/ 7|KR_SS +'%@w& ?j{;j{X5zgC N^ z|_R)lH 5{orZĉR[\ iVI*V^[Ҹo:e{(3/8_?Zj~Q+A#3<~vភ ƹ/x'fTn^`i5 :^M]{D-㛆^l^pn9{S~{ +؛)V}a"5a]14~`XUl; Y9[Ʀ}{&ϣ^^B|_~1A>6{o%!C{ƬJY5{_T>vtx{7~wߤ㾏o{L^?/gX'D/ؠ&Z^[B17OuX6M|Ϛ>qYM_ o7mΕy;H12U/r5~^c!&/llr{ 1r{"ڕS){p{FCǭ~(Sgm~iS\ 3v#a 6ս~y0{ !E/V?znS.1J{G_@kxob9r"y4GI(\t2mkᮐJ/bɯ}j?v[9Mܝn--=% =:ύUs6˼n'̺͕wv!,^zz^J/WέRF>{9weswQ]xj]dW]k_>;\.lz;XąDJ?SB}Y|c-YtSW;iD|}uxvq*]΋g'SYo l J8,=rZm~}m^9,+*scvK/L/^׎=w_8{'Xy+E+Ԩߔzr" L9/O|&jˤAn Şz3VΗw 2䰜?8W>bIsGi>X/2Lze_ E}-~0̫/8]fݤfŇT^6"aϖE"OyE/~RlՏ b6-Vײ<6c7_:@].n(XԺ>`u1L B:+FHom(ki> _ǥĕVP*֫I;Bz>~^Qz8ްzܑ Gp5\h>9\o2|.6+y?&z]KK[*E,P( ˛}W_n;z;" :I>Iݵo>ʸϏyJ~O aZlDG}QZح}\lѸ\K/hкJWdvuּ*]p޺M%g*./.xjL˓ J(>K-].jL|\ ~ą[%wPn2bZFLԥŎ \.etYZ7fw ^3E7er8}>ذog|)aWӄ&?91빏oqM|jpKRLJJ"}cl%明ʭ:Uݬ>9O\^ݻ/=XkrUs/,fq)rDk5.;* z_|* 9!@G)쀗jglT&Bvt᠟3'> +f7>Ce\ETnѓ=H>L-v+B~M&Vn_e"s1oقꉕD[I$I_"H +c BV[yn߷o. +kS'8_jn{}ԅsETg4?"Zl{0vgP~[ٟ/}KB,Yuѿ$O,z]6:!jg[|Q؝_j, K/رvzV 9Q'm$!<;g/,;;yޅsl[ޖמ?J^Fz0B/Qrc*58<\.h̯_n6;_y) &R1hQ*5A]*r~{6`xZp1uXK]7|OpE򕟬{>Qzb{l#x} Ub% vyg%ղt̵}Nj$DC$Xrrb|طۣ:}F&9Lx##":/<]Նԃ)g} zcnJQ-*6>%[IL|L)> 7@q,Kr"PXc4͚WM(MWSM1%{'C0N +]nP8-2aaTz,^ +nz&  ;hi[|kÏ͕Ի\>3<9*+G/y24? ׷w'>cIgxRY>> =Hv^!`5Gyq$~qhD8,ڠ(_aR.~^;cPО¡= hu!bQ):B4)tƙkJS Xr6C`xf,F vl;%.s4C֔oe$Ȼk4Wa|B<4l rtF.uDlßzvdv~uTؗor nn+W^]VKuW7cm,9sXқwŝs).mA/dcteg|mg%'#B鹴|EkPFOFnl`#y:ŽmX5rcSX5!q񱨛ı 8ya`)sح.t&2D%+oCXS(Y-{H0-DP矉K̮)fXOiNh#B@=yr2#!6k`x?QΈ%BӏL1>)/`í7?Dڟ?[=1HP%ĶRL<#㳑)Yo*wFv}e0KAS}i`mWO듿&C_rUOOOl5n'%y,8rR0r{cur>6r \́/mYorƜYD)kw#G&].,,>5|\y6.f/:Fꛝ+ɚo2N1~cgP>=R:yfD%Ѧ`oR1r鳌XӎgAo#H{D]"ۄlt+ v={bKZ!?iwrgҼk#b=LRdLT<+43zY;ceBGG%)j) + C`}_^08鋵)aR7ur$\dDG1b!{ g_F0V;;r9̓4 1D]_yxp3U]|+sWDžG /ka[d\O@6p6_| Wr cPĀlIʔÄ Z[wG_rso 䲾xuK&WyT +ߍ4]gu="":242]PQ82-']j\P)66 Oi۾+-:u+\;={%Gp~̸:0 u7eslHl\ KaQY?Zv;exG Dmم*|s{;fSOq@lo'm,햎\8%ݓڻIe:k΍ &EEӽ)AFXwE"/@ 8u\ı}嘟.PV wtQ}MNu`G&9tyoćȗ HTQn,dpLL.O%Ѯ"kDM*meIAP7U},}Z\x.>Ɖm\ɟ\}!=](!ZyQ:O±|=sS6oXSF)UՇ'we.n@y}3J5h!+1ƵԺOçWMWތOFu6[:[ +oKU|꿭WU/We~(] Ȝ%OizQ%ړl|*Urhw]gK_ʥ\py[na:uwtZxJWMv;Ds6~vX6eij٨(/[+W3n20qKS^sPxʗP>eH=U65N!ex&Ž汯r9}2|)NN\~S"TjpZU2*HG(Ff9gh$+Y!P ½]7ir/9'9zep*R0} 2t +g3$^َbߴrѸn3(ujF{_ WŃM.5jz#N.UAH`p 2/}krR=l%1NV>,KdWX'TJdz>yc5cA`l"UOx(~L)'j*KHz,]YM@mݘ榚_ǒ櫍 P0_m%Ey2_Yk7xū`X+0/rȸK<M) {/.yZu۴gx9j !؈ G52w[{~G,2ݜhR +>c0($J-+닫>$C0b&l̵3GNjKץF {:A`ϱh͛EE^aѫzF4〒MR_=>H'P +{U槺D0%nj{S`~=qWui.Z + N~ +xM*~*峝61, Œzy:{[& TrOTճ!n%/v>඼\Sos'NUŷePzQ 螛wd5cv8+l<Ą{#uDsdKId:6t@P\ vײ\u&Xj#Sq,d An%3 | j;bXQ]w" Aj͕ 9ׁj$d48p\ W5|d(obr8ek}ib>óQ)%|T5ϖ>YU9.'9_`s 03я뙍z@oF?= C?lQ8 tn<|[Λ@[(wʎivaR~ (- X*-iYgx5ASf2$`N!&D4{aS cޗ!FT5!sJ7P_Y xfA0|:@po@/R)3Vfԓa`wH,ؼD}fL| Xҿ Z&bys=}2f,BB~T؅8 A,Nne wA+&M;`сYޅrlQw#bh;gKCRHCP<[rCەc#Wޱfn ǂ}X~8T6y!cAp$ıa/X"!DN,/.娜.,pN< $Y OkyrL`>8{?b#`2WhB#ؤu;3R>VF2QlwcU{ci)JrbfM{:{#h 4~O^$E)x!-'?q32g^a\#'ڣ3NשeG0Ff佲{:wCATDu^gadMtlX9o\ڸ;CÓv 3]ȥ  ;}8Eu_rh;Xz̏sc7{S= ;yZ~5{+v-ڧڻK<+٪Te['M?UnSҎ ;>$n L&,}ӈᓵVYWUW##ee&uS'X]+6]gqq') 0Ys$fSfރ<3O|e~+ٿ^ߺoqS~\0h3H\Q olv:֕`Wc]ag|ױ'`Wc]iJ[%1BۮX2 Oao;fыq_UdKq>?nǸxa7|zR6hvڕޟ*>?99(Wox +ĽAkxƸL 0vu۪ ҕ@!| \$8e4ǔx*3/dzgtIu_1F(TN8^y&JN5]uWhs:+qr,oTAE=.B5D1'J؇ p*'E]< jb5%?6P6@[jƕTM數@'4`$yFT$*]BN8]EPtЋ,*ȂmdI5MyH/s'*TU`𻜪q*^8BN`҆袦+$zX ?X0'DZ" XAI,`P^8-2؋)$, @U$ϩi\1 )BTYE&Β& Êa UI'Kt -ҰNI=BԠ EEb !*@ˊ1 Kt"I4 +"h6GlX8`tE/Ȱ>PT$^8wdUdUBq]lI x?!+~Np+o  󂪋 ~樚щ[*RHi!"NN_0Z@FVI9X* +v$Ep ˓4Mx0q 5!HiRp?&LFD! @6.8@m`10y:6_E㰅#HC!Keq؎jCVDq+)6 +U7y~/ +p0'TܜSC,`S)0^dtH"r|~Q[@"6_,"AtFő e%: 3eDXF$ +h Kd*@qِ ȄT5`0HLI@$PDB*@@*Q.4-d $Lv` A[@Nx5 "@> +G(`PPSTt#̕G*}`NqTvOdͰb+3~ sB-`a5 &%@6AP LP-U86C +%)2%@,C:`-x*;i d&PI D }kP + +$QE[{eQ7ڠ8UTېp``9@$@ ‘BD +2l(QyЌd{DWR P5"@ʀє Hqj%Pب3x`TEeh DOi" = +}򐁣ℬq<*L4"DA͕pӀ,$@)l%85F!O-X8" +PRαMLO+(kH Zcj1"J' ©9f(0H9*JNM@B9Jm`'H+JไMzl%DTD$*% ɱ@BZ5.F$'( .!Q ǑMZ +amS{ : nJVnڂ!OX*Е,#"mhQ7%DnDn1mc(*pMТ]"%+XlzD Qx@ՙH EƱL:Dʮ43v -82 j@|0ỳl( 6/hr/ +!K4%k"dO VGDZ d*G@dUlWQ#O睋r'ӵ)[ zx\*O=NS`3Zh(2_2*N;()' 2^[[Q 5ʼnY0Ca 'C w@%P'P|\t esD\EԈ-du9 +BED]AàLlA#t_BZ8fFu4h[ + !x8W+N0A"7V 4  22L#^:4С?{Fl]Uk5)!YkMFɏm2Ds*1'҂7,lUQ8"AQD: mM`g -`^IP~5<dk83-l ( +Dđc}3<5 uM`ˢ&X$00%",$W48 `s$ 0A ʆHA&?N$QpKP.M'zlãfcG_BphIR -."AztgRF :&%K.ݢ +d +. ֖ƨq$P8ŒC'Dض[P!;ĉ!&swb.-G$YڋLa<ֈ +c]5L;mpafrNC*QXx]$xK#N&8BK"gX% Hsh=ihSZ$fGO;ƅza_+9(Ц1L0PIDLCD7`̧5^`0ԕ<:G%h% +P-g43q'9>a( d{,G U-D3#5t2;t|1.g0|l׮N Ȅ(SnBKxHΓ>XMa+A8?Fp,SLA HFDG? +QyYq{+1K=2 h#Ȣ 4a1Ht [_P%pGτ-`?Hip"iNh!\xX-|}r W0K*;eӱM\ tD@Q}P@2ēM@8@]\(1|"L⪶z?"S +cZFAu"h;5-HH2`[8{* :HՉd9x𵃲7:56hfU0e!J f1 ^gC$PimN#VCΣc,0O 1;PNwb 0t'@ϧn5I҂N&чǸ:^q:Ġ +&@{&,ئA70fЊ !UC6@A`)Q- [VUp6>J, ptPPQWOdsL *xM,U6HVal$UA6(Ly@h "c?Lcwh1ZH\DC cQϹɀaP/Cl +KSMY܁6 XAfglU0ف> - `l I^NO<0>E5^6_QҜ +ќ& h 2<3b Mg MK`QV YČ$F}Etaxl.Y#9 mEAfBHN#Z'X\5cF@7+d8(jBbfB[^` lX s3N/Hy1in Tlp^pqA9a!f098GE FCK, ȢBiBa!q9;2.cl%#7B(2uC3)$$ S-hH wgTcS1O ]ӆCP F>̀V7F<7" +}S Z$RفԲ$jX'04[ufpb=Oi|wyWʢ2KgUk`0ی!ީrF4aaWK!^r$; uGѠqġT1xӿ[O •*`EgJ?#tH{LHE o7`-xCW: (9`-pH=g2b~/ks=-DP϶@$5a+SGH4=gcuc=}':թ{}"&U<82[#/ M=p㕜7 +…Yh/F{`81uc`z[;k]*`vCc{'8SX^H?6{0F<]cT]0Zd@u_2Wm{T +E +@'kP0Wc\vUF1Sg:evBDs; 8׻|FnNir{-kl|yc)<7nc?fj!c<'*x8j)lvdB50gϩ\QՂ,%ih7Hatbv~ t\B&^s~b\Y=vCCDB !h q)ʡ"Rod-'B_8#=#cG݉^ ɿy\YlWoX7+p#cډ㾜S{ +P"832ʆ0g]nǷ ev!J$\v׍3w + UثS$}vVd/> aϽ?:/KHId[Ge//GΨ}\Zxs|=-aPfbl=OlI-0Gp_WCn~}F̙;-ug|>|pVAD`!VXiuY'>Z-DW`9?D|}#*@<׷~w DDۃuADS"`'A\x|F̐T +xjm⛀u +cf`u:2z/SuT:Ax +G# О̼F^Ɯ7{:x |EK (`=Srey|BE +pR с:g&I߸`,쉠s8c+YRhYr` +~`J$Xՠ]r8PBӁ'n@~ +8%2>Pv7:)hL=PS66u۝fs ho_ڢ! :_'P1-91\mp T!e} \A¸:tQ3sGƄDpX"sا肀TRZZZ/lJŒ{թ;! |T?0"&6Ϥ|1'hK [2f13ETVO/>m'0@?/ʇ<` T y6NWB`bMw@^ˆZ|oL}p rl[pJX g @D/^DɅI͇ݝ]¥{(C- Tǖh!rss]0wz ձAh(EϑиZ"ϖ`)L|-Yb ^"O[5Ѳ!8{7Ee7J@atݡ,^PUF0-8u5ƚa?[Tkp|y#2}2 +&Twg`A]L,amlr2EF܊mIXeU_;/'Aw\38f6*ؠ_֠r'Wˌ:۟*gD$F-h\xڈ7wIZX)r>jH?ٟGu2 nc)MTȾEZxjpnBݮ5/'Jh +&=Þ;2?(ZnFĥu Ē#!yӠS*$ K,hL1vj箋HEC9@P}+Hz{yO;_X1u%ώȁ +w +Byn}Y{޷B%q]Dmo '%ۄtP)Ɔ#pnwQȐ͒: 61?wٶ<`hm a[|4 +dn!CHېk5ПOFrt;Wc5b$UԲaS:M^&ANv[P>Pvrȉb[V|;x6鮐_;#@&rҼK؈ ~BV|~~8t(*nTxL-nM 19A5*Y1s9Dc}1Gy7Ȥ z cF3bse&*U7ϯsQCK_fs\aĭ/@yyYz\@6}K.t|uP(Z0vF J_ (̶!W el{Β)<~ ;cJŒtӎ!"Q|lW)-sv2{q^-6xщIcRUw}bQ=Qrj(,OF`[?3*)`@ kew8ЧȬ|L$,?;ٺp,G#$ME8 YjJB7;nfo6N%0͆_< Kvל۹2n1=Q#8ݶ$V{˃d$ , 5[ŧzL/@z!2/KKL"*18.g!ǣ̪>VÃfm;q_8ܕnkwf(>m#2Zö~8?B{HN-ή{ N*.`_ǾC +[ʚwñd7Wob0W!\nd$A<ng޾j[v!ch aZ6zF?mS?`+Ⱥ^%=M*TaY!+`?1;`C7bpt/3: rB`۰c*@x"  vNpX0\7HJt;K2^춏mjw IHFT9D)oWvQpys+?:}R#GGP߀w]B̢i+~|aTxb8TV@I!DH :ւHu"[34/ݽ^_dNB\ ^{1(ע)Ȋ^5l`ulS"T";1|EY0EB{ME }tp&r)N7X<:`E&zO!lƀ",  +{$(vPbk1WҘx# +#4"͈M."Aunln>)`Py;/JY wجu77FþE[bC`J[=Pv,R 2l҈ WJ3Pd>@HIǭ^G͢n3Fr9Hwwoeo(F)rs$wR;xx2)x xm]\X]@{/s/.PG_:Xc{h? _[8u/M Up9P?3Bk&\/ -uҞ"v.ʖ,]dw"RH7૶4;oIbpbkf)=F2bĈSV1Ϥ.ƹ_5FȢ+Gy%m=!*8aͼ) + +}kg]#@3~{!"#";f.ybAwAP5pbΡ؆rAMI$G> p̑ n8Ԩ3UIL}lqͥ܄{7zXD!=zCV{O1z?ZXTV#@ o/pTe~oׇ#~,o5NpT.cЗ~~ +ZG|Ac!Г<".$bZ~!iYR;Hml2? f_j`W.'@ttCĈ")mޅ=n 0I ]{p[*Ϩ5 +%=xA' S/]GQ%H E `ܑTW\g=]'h QHB41Dɩ,jz\zaC;V#Z1!>K)r&p 8EEZү@I`ؑ.VeO ;[Fs}w!qȁ] ƒ#<reNSC1 u桇4o'q,7(.ay'CxUwFeod9R_>-k#"[I@S}\X&|2 s*H%0pmNPyJnY J9V#̔/?=b!_ BLAlI#5[gud l[[Dir ucRmEoGrM^]_$3Fa9~j ~dBDhڪ Aad1"}k\DIh TUMf׋BGվ2,է稐a3 si-Śs-z@̎ +\sz!nlW^`ߓ_~2DfDWND _"<$ X%{'AhH.Mhq=⽝${KY&y3 #\{@nH&?ݯf `;iw6"|I/І~=[QKvr`DIaJ:SHNbˈH"#R3#3AANHpz!~ⴞH:xd$D ߖ7O ~ܱ.H6#6yIe&];p6`)`w)" o%K [2PyDK8\dB_=={dF=}rϢPx'ز2B8^1p 41wTIˏAGifPniAB:N7u+ء?QdqMݬC^"dIho0x-QE~|ST>DӯDu d@yZeQ>Za!v bԳ#bW:8O5=GVJ1_XS?Σr6CDgBT/uxrdy#^⠘Z_O萋8nk#k*wuip;RK*~ґ<>wOoA=^lsWi[͊4QQHv,KL 뜵eGn1"Nş|9OY' Sx,>4ӋOֲAI[%m2T&N 9qb=mC*A%ޣ2( s(>/JM/j*eS/_%^@cUtYtz WE6%^~)˿b)UPe[U bZ9f+F{2syY]6eq~< +3+/w<6Wٻ 3I  #wNvF嫶oрlr1[&̝evKs z'HN~%sDO6˞Tjڳu8H}v>\rxd^8LvqQ$O|ly}_y.q^l' h N6 &~{@XVA>;&)o q= 1b؊Y(+7PkB(ݞ[TYǍ7O@{pv\/Qkq'c(_\,\lc OZXz|Jo Q߄Fh1HjcTNޑJE@/- g> +$Yb-:ـsZ7[>:KRk,2\tj= ؠ +ؚv0TnD|Sd%xwB{]r#yПP0*R՞;Zo>&7<u@\Q=^DZha&C~Hx> |3".R/8D~/i]7rWdVvM7R&x[7oV7DMKoV3YˍncMfǗ "G!J`0S5[I"U[4X`{ k*t=G +nmt)7 wcl7]Q#hkۃQ +]XR1$ 0R`" kvzާ D@gdX M_'OؤL%DG 0Ih9\`kfI)d}q:u2 *ԆxQqZpz?c, 3mP +"tK^,"f_%Y@EyԼC16jxDn\g2R +ǯslw늪oG-iEХ i%7[# * A.%z`]uE ,ѻ}I{I>v%m4gAv d7q 'Ic-vrx`C`Bk?,8x<Ƥ,Çkv*N7ƚzvn_l[2' ?[uqpw -N&{q/VJL)pοӏ8b@s4E`,*JMm^XIS1fADxFaВWcjEڣOИ`ZsQ~3׀=`٦S6ϨyEc>sfF'uu+ϣ3:L=%x٨ljK406AlSKJlyWY]dG1G&{a‡8ytnlJc<ͱ + 8D(=-GQEص;`ȟ[nt|thź;p`m.ߎ/`> +Hl5n|e^+c {sހ=jl$-_ >dz/̳k 20'ݭ{۸\ӘsxƑuww]{gtja1d +bC%S22-*z8n1m[49ּ[T2xL06Htm$c}pPׯL~ڐ8HKnxslp*\žQ8eɨs+fHywCa\;4\\ȭk r֨hX,qB\GjxnnN@ՎsF,B6.NH;<!膪Ц'ŕ8u8@s_}P/ E׿?qfMO--NӧI;2[ɽ%.oɣpLFؑϑq OCL1M 1Wx@TxM@ۅ<{6WO,'gj<.r&!r%Vy6j Qv\܍»4-m\vf^G|a~%cN@Ty;Q;(Cٟ W@o[ 92FXJq'$Pu&-m(Ȋ;ɲ쵑WڭWBJҎ0Wh5S7QJ4cw ,[u>YZg3v;#O JrQ` ަZ6Ӂb%{ۿ?(G0],Q[PҚ7PSz#&082>ve.`Ob/jQ%`TGDPP`ulZeZz C/ID + |mPFV=]ˉKVKH:0\ R_ʤ!99zT;:^S9-Ԣ:Jw-=RE7RmXI"Bl3'_5ZP_|OAV)/#c`*T|woܥ&W2bں١ҼE~ԩ @{KY5H ߫pij P3TMb%UQ9RsEeSkTNf\MH6޺nds:Jr&Ǫ'W%l< (ҚтY60Vg`Nm9ų6X:яP[liO +)jI1C{W uTiRl4 Ly +ؾ :/nл(#}C}S?-_kiWۨbL-,,:6S@4r{u}Úl.C/k m^:XWW1`2@" +%1 "pwq0T+介[8ϙ [+kep!;:xnUiuMPQG@ +,_rʥR8p%Xl _H-DW; p,2+&ɌiT߃~ 4*!.ʰDDRLopXiI{KPv]n$\6(!f+E!KЇ4o(b&|}19դǹ[Srq/~!Ux `pǞ<:׎W:|oSÆ|Y-<i7q_SY%mT=/]hH"In_qM.ɒQm66Փ)`](qJ#i/:/ +-= uB`,C r^XHgWqhQ7<ϋ P,g0GSz6UZ]C̙ļ/knۗ (78G"YNzD?Bƈf uDIuj<s,.j?&bWij⁈e2'S7dXP4)$0B8V(PNM٩v*#oi 6d0![ēlx=|p GnwfKaA2yH}O/- A9 m])@d1%.D\ڟ43C)kہϫuY)};a*=_==> +F +fѼB<e +Z̃Ԉ=N/oۓ5 `mR0R655vDB~H0ֻm{|=\(<S*~ xIޟ0YLG?V Gڜ$U&0G &0sܖsd`@2i@T+ #tH[H͙{)*x)J,_~Gx}iߥ$>p MΕ^ oQѲ=yJSٳgZi~{EBbl7JNq^/ 5S2kWWu + ZDQc-_Z!tY@9Քۺ~gF2ǫ蓇LR\IlJlFO/=Vc]1Go5ՕVMi`HRR&tVڕg>2@`e+;:+}+gZ_*Wi4*,Efg=3I|zd,[ɝUc9rW<5xZ}f9!u}<}ҙbe"Z" u lOb Y}p- W3}3&9 1B;(+ +D6]n|c̦#_P/"U}# lAB!KLqGAqEgS.Sĺ`xnbJ4~cN0&X+LHs!{AiccF *ܶw#z)ٳ+:[zNNs>D.x6U1O­}mwq6N^;*P"n(\]Je.  7Y:'ƊJtWn*jns!f$sJ4$)񳹋κ'!)HW*1˪.!RbgzիB*-8QȄhQ%ZxO"tV7gV9 +3 &Y\") M8_ޜlq>&e d*X>S*$ Vz\::MVO}w/pU5$ +2O"^{POTA0{1Rcz<*' Fd̹ 'A@ Vy1kD߹oP< X׋n +5o걉=02L@^ XFSe@^5wHx^i &NuDq[ZZ6~8c(e{"F +DL<ő{K[¥zM*W[$NɅ9(y RzPu.]r}n<9¢w߂lkDn)j, 󉾟H`m& J՛hՃb<~9dK9Hz+ňsuǩOhPȸiXAG"zQz& "2ˆl7eIJk͈H-^?­^v;mwBI%$\q0}v0'n M ,. B !!F>|[p>ռ]` a$u|_ƒA:O~r;[!\ ʥ {Tf&Elb\'ɉ_^۰jKǿgQM +S_ VOM4SŪ\q)׫/s7Er;Pt9`q+B97''yqjDJMy'g'X-rj +ei Mޅ"^qYGTG@5KLXcꖀl/5%M;"wZamwCEHɽ[7Z=kE`su9Lhi=M-'LU`%U5Fw⽊(n HHczyVP'U# /'S!:m$O{ͦPeQڎC,̑_T +}_/^!cg}_E@ +rK=kPRw@5.SXp%}i &σ$pyyP3\|i̪m [F}qʰ'R%0э\./99GwF}g1~fDJX5yVEDMWIgj.P'G[li_!Jvཛྷ<2¦XC)ӂN/%˧PFUM٦G0ѝZeF+6&i8cR?4_"Yá@mÜpS,a %:XQ +ŧnq_F[D"g/>@ dzk[2 2k##vx"xab k#ԉhf( e]1ɑcn2v>{tr>D-,)BzݘvgXm!/^Fu#%($I>:Fl J+_ǡ|M\ 7Y/u8]'2:!w\@lja3_^P2ˇ4s[1~+kADl/q +D wgF _2 j[A ?!:V-V,{Hp`sxM~0xy~rp4ڤhy` "l)!f:GG  !xl-GHȏcŶ2ߋ˜ɐcP\ګddG>ҹ;‡iZSHݰ*'8$s@ST"M+9~HHr)NSY @let)2)i$< F@0zݕʄ6} [\Wǧ՞^Ȥt! [B}e=. +"Ss|btA|&O%*׬gڶ1AStAnAb0kze#T>ʷ (.vE*:HܗBT~iW^Fb`/ĭ'IfȬ"=[˥G ,W2( ݥU)~#K &/@ŸՕ|2Sbw>'>#$Ū)) EF, +F#UBƽD2SRM_r9]>ށЪCLxP1N}ZzJRC cRoN_VMzPoԉcw +ηW#ֶvNE|8T1ap~ftB.MziwxTDذrAb +1B(תb3^Ub2#̾pj!sk6edO}"~,Fz_g5{1_5r\ehKx \\A_Q+(b6ʂgKriL/jm g a#{!w6=oE;be \v+h5iqQ i:!B^,Pwhlu8^ ̙յ yØ_>"$)0d/(15E<ȹ!Ҥn۲u4Cz^]KXn<8Un; "&3-"n}ck @gl0y#D0DXz 1MXܤF. w4k(5–N\3>XtݹE5˧ WhC5UFb'[Ә?UѠ\e`V1EL{{'~U$ +ŚI rs1v"5y܀3W*f꛳[]=@PIW׎}6N 慈9` ~4oA z6}YYO@lGSXz"KIYIy̱\8&?(Ŝ^Rz%n3"ZxRxキeς\#!M?Z̙WLycPoy^ k*SrFD&nI3`n> b^$[6c/8/JXAN)h[(ɊG8Ad+tDjTXV\U~l׀1TZP;Jb8\EWA%HثT>lF`.mO{ 2G[~f(6qV*DX,M䦩_EQs"TK]pzLPr[ivݗH/0(i$ߞū')ؑF}0;8T"Q#J* ױև,:8_[cm@%=KJej@"Rn#m<(!@'ӏF3[eD2;58mZX4Ȩ/(#҇ıkj b;ߌ1z}ѼFʵR-1ɖ]jtNB%8f`]`@0XudDt3HLߎ#F&R4QцS%f9ZXctg1/V]F2SF$Af CeQ.df?[*KݚoEPeiG:SDqGiMTnUn)"E^Ic($;{,R%ZeqQ)΍TM25B8RbdJ_m%](|b,m...36te:,|{}.7 sU@DW Om 3Cgz.?W2v/Ln<ש>)|:IhgY1u3P6|nezKz]ZѶi8qxcAH#b15Wݵ1"1)m9Gb+DG?/o%>pڍXh ЄĂsUKfhIs@%&֢iNY\r5!j߮9,Qp1A\e(Z:%fk/LXMPߙN-H;z=XD;4)w-K*h:C_(“fˆ[8܌ld"X ƫC"%E$JØ˧&.KP.x~vwo}߼_˿x/h\'_//ߴe_߿?O??O0F endstream endobj 6 0 obj [5 0 R] endobj 20 0 obj <> endobj xref 0 21 0000000000 65535 f +0000000016 00000 n +0000000144 00000 n +0000027685 00000 n +0000000000 00000 f +0000045164 00000 n +0000107718 00000 n +0000027736 00000 n +0000028068 00000 n +0000045463 00000 n +0000045350 00000 n +0000044121 00000 n +0000044603 00000 n +0000044651 00000 n +0000045234 00000 n +0000045265 00000 n +0000045536 00000 n +0000045710 00000 n +0000046995 00000 n +0000058015 00000 n +0000107741 00000 n +trailer <]>> startxref 107939 %%EOF \ No newline at end of file diff --git a/docs/_site/artwork/draco3d-mark.svg b/docs/_site/artwork/draco3d-mark.svg new file mode 100644 index 0000000..11ff9b9 --- /dev/null +++ b/docs/_site/artwork/draco3d-mark.svg @@ -0,0 +1,306 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_site/artwork/draco3d-vert-180x137.png b/docs/_site/artwork/draco3d-vert-180x137.png new file mode 100644 index 0000000000000000000000000000000000000000..845e5df74f6afa31bc1dd33a0e71c807a1313f3c GIT binary patch literal 9189 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

JKS?wBHFA4T=ya2zN?neyodE%XZTNz%Kf zo;=(sz6{8VMW6_(uuat^5289xzCZ=_`csE2@!cwkR36Xt#5qLEbr@vdeb&FG7-Tl@ z?BCSIp~$vFvwm39It4tT7YdR(^9f+mM5|9n|NHJsKlTfr_4ECxBIa02W*w`2WEIpxWAbxY?+ZzyRGagTIkbn36ElnyCtN8q8Fu3xh|w$w(f zx(R;9xzfjwWf|qIeI>D00Y8lV3qJ#HFz|^Hh}KQAri@l4z5*u2mkD zm5{2mVGs`MeQ+rXqfx(&*Xd;LLSVS79v!>2oQ-%AB{wOG5hc_Y|p~-M`u2 zq#d1MPGA>J5ONs~;%2O{(>GM{YN<+iBA@E?WA@c-y47NQ=BJ40krL5_F&f#OfuAGV z7d)myT@vn(dFo~ECI7TX@GlsmF=>u;{rp*)`>4IUL8KJ{+!@8HN5T{Lzv(x>qEO|M zn*;j~Bn&|;C(Q4(X}TU|A{E z#T{uC=!P2C=u^bf32}KKc*KN)wm!}7%7Mp-J>!;_gzFsmhF;^79vG6@lt;Z8dCEI@ z;hN`@{=u8^Co02+sj%g>meobr>Y<(JKz_ttphF%bS%;Y3^wbyRo^Z#+>F93^T8~lH_~7TR$MG<64PMQu;Jvc9lDvadxF<(mP}jnwBR`(E zDlnTp=&G4Gm1RhuG!Fj#lsR5R&mnzBJl>RDL}TZ|z}orUu*CuDSRquC5C9;e{_l@~ z$kYJ*UW81&U;Efw9zJHHYgj>wo9M$to{s{-gh56FU5yX^5f7c<0>pPyJRa#fNWD$& zvLCilH6)pr>qg;+;WKI5t9LZzbhvVJ*Fq#?FLNHRn66%?DnB|=pF9rseYKb1QtS3z zIU`-QkZ!2hys?@0^ua;-7<<2;_u`G%DVdj8&&iZHG95i({gD1ups-a+{*hhZV-8l% zs!QIM9d@0@_gCPOaH6x&#bR`C06~v5Q^|DDK64X?%8c?)n$<;#Zas}u8K-c!l*@`LEM1U{y{7)FN7Xh{XG9)P)$TD7iSbQ1(L`2f z7Pir3ww5>~Qn^itNEtdkMs;xAiTLyg!NlTzqnp)Jnjdm-z}WSp*CWq8k?x5C+=wW# zS>d0bin!y0-?}Ib9?cQk!=qG_Kl!3u5hB@-hx*uayEp^whr%ocGUoa@KNQrwzUlR8 z-Xca>nr;_wF>+@W*#(Q!+7pgpvOn}6c>t#gp0C4g20iPm^k_Z~XPEv~e;N@e7Phd7 z(eBRLO#3xWIP%XsOm(4&s8Osb*Ky&6T7y;t#p2}58uED8?B|~uE*Qro%!8?=(k|U88NbpDik9A$%WL=)Qe8-)W)**Q z7EHq@@|<*GDeds_*5{1_+Ut`i8Jtek^Q+xaHbTH5Y;RRw4Qo*_dFTm%Z_VlJ(mXo( zUxJ@l-c!aB<1+NDS<&rgzCM~!e+*x9JMiE{6hb21t~3p-qsl?{5w)Y(`VB#SV;5aS z^9w}@hUW!sT5AmS%iuRMPq`4B3%I!kF^{&dR;y6PW!ML8mI#nU=<~!kMU-hfWOH2m zp^7}yA#C@;BEbX}u-THCu1#gIT+v)A{_nu2N8CYFLoA~8Zc@#All9RZ7eNB}5Q!Zq zT1p|+?8ChkS+Eb${HSnjF}TAgP*gpLZU%Jb4;-013tFyAKjY_Ko&R9zC~*^udqDr% zi^SgCUrqC%2an84!Td0zZ@91+_3oMq>jcmH`D+yTxca5E(ts=Z(-aOFzY^aw;tqc@ z$X$Y=#nG=S?Nhg8Hd(}6DO)%E)6Q=!<-Cb>71O#ByVH&^hwam%FbM!`a)i`XK(CnmImPjYfCNpQBLH13L(MvMXvF^k*4k_& literal 0 HcmV?d00001 diff --git a/docs/_site/artwork/draco3d-vert.ai b/docs/_site/artwork/draco3d-vert.ai new file mode 100644 index 0000000..0ff3ffd --- /dev/null +++ b/docs/_site/artwork/draco3d-vert.ai @@ -0,0 +1,424 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[5 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + Adobe Illustrator CC 2015.3 (Macintosh) + 2016-10-31T10:58:13-05:00 + 2016-10-31T10:58:13-05:00 + 2016-10-31T10:58:13-05:00 + + + + 256 + 196 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAxAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FUu1/zFofl7S5tV1u+h0/T4BWS4nYKteyjuzHso3PbFXzX+YP/ADmjFHJJZ+RNMEwF VGraiGCntWO2Uq3yLsPdcVeE+ZPzv/NfzE7nUvM16IpK1trWT6pDQ/smO39NSP8AWrirC7i5uLiQ y3ErzSHq8jFm+81xVu1vLy0lEtpPJbyjpJE7I3j1Ug4qzny1+fP5ueXXX6j5lu5oVP8AvPet9cjI /lpcepxH+qRir3r8vf8AnM/TLuSKy886aNPkYhf0rYcpLep7yQMWlQe6s/yGKvpDSdY0rWNPh1LS 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 nxf33Gn7NK02pir/AP/Z + + + + 1 + False + False + + 6.944444 + 6.944444 + Inches + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + Document + application/pdf + + + DRACO_ID_vert + + + proof:pdf + uuid:6436b92d-aa49-0745-82a6-f812a072dafa + uuid:f9e66d04-1cc9-fa42-90d0-b17bb78aa951 + Adobe PDF library 15.00 + + + + + + + + + + + + + + + + + + + + + + + + + endstream endobj 3 0 obj <> endobj 7 0 obj <>/Resources<>/Properties<>>>/Thumb 11 0 R/TrimBox[0.0 0.0 500.0 500.0]/Type/Page>> endobj 8 0 obj <>stream +HWɮd ߯? a6U^ +Nuw9$u$ 0 G%QC>9n*ea=RG#=S(l14!)𷗶csZ8Nkv]_lLXdC+PZ)^/2( :5AD\w]KO}q4긚) +opK2MX;r *0l|hu*R3}% / v+5lI>~a0,ZG#b`[0~s29"/xkn=]@Y8KҌf ?gj(uKN[?}ۖ*^W8u$-|iׅX!+"3^̏@rQ3pfVb:0n{)!1L>>+Ux'H6\0*e1p{S\e7k81G3[-ԒάJm`wxc^gem-+dߡ(}7,(mNI$ڝjg ED$}qӷVq%l먡|q]'sΟ>;!1X +*܎\ HAp5"WZwY Z7U%so RcFDO~l]P A U)mު|9!t pM-o `߬T d`F\'J0,>qX#ixÍ(`ǘXRYHOR((Ǐ2oF02`BT,Bӎ.Ϭ z"G3#%h AAcȣQh _xlE:γ %^c3|n&EzNxQ(Jx?mj,5fi)$Gil i +oE.; +b~92NPߴBxj0(yN,YzJҪWB2}GRsIp?렞 +ޗwDy@?Un{jB{%|3 t``T̄T)6g5yX -K&qN씁MOgia#+;sNli>f$2)"'0ޠ߬[#"?"f#*-qrS>~T%i:UMs,%/w70j4CGYh<'xOj]-2V+P +1Q }*34% +dje +: sZk67Nbi|y6˲bu47.4yz`ohP :~(bNxGH1Ȉ/&Ӗ$4ЪlADXpXc.hA6'x߱OHkpo`L#x n1w?iJ%}be âs+on5hЕ*:bbYߗK#24C[ 1u M|Y n8iX.4\,wÍr7pC f77.I|ۛ9w̆u˖UlmRͶBcãKh_<|Y9 qסw܍YPg[({m"g"W@CR]BU<tCӿ-1uF%Ştʿtk骷ޚtk/MW?~kJt{UߤWiM3뻈K*e4UȰ|m +4U!F5< 9߿\E s둉k0ណH׌1"ׇt +L%M N01!Gr, aC`Tp bJ; OTc }!* +ӆzeN%@TD"سTm62{fhv ۞Jeq42dsF͕ΐiO < Mo}uhjC7%ytGed$<`DsHEfJ:a0$v6H'3B2 Nm0b#zJ]`JI Cc],0r@zb 7P;p˴E6 g PV]Lt f&8T <Xa0"JTاO6 +I +OH܌xlGrM@66ɒ,$mmHharMzrfiVў%n)*H]8">LIa@@GN* a֌ %QvU.4 jn)(Spfj ,s u4̑ΜÂXśqaH' +`pK< ++"jrhRn+c*FRF$LUj5QȒЉC|ix$& V0u BEbBW0Mٛ~p=f . :)KB%A$YP$ÿ.,;rkYOOz+h\@/>mOdB"A4XafuA%}M9QܯGQ_{ OzsѸ sܡZ?c HnGGλeسA?IjSHG%sk5[\ J} 2V6)nΰB4$iz@G.^L E,ζUrk2Y{Nrn)U]hxQ8o/À஫ +b> +=T`>'#mȃZYЧ@V&H. qh79dSYٖ0~<$Mmه"r刬) ;+KatT ;I&səJt`V|u+csi nfOGPr 8_RtRm|TqZ +R` WC8cM S(붙[ iT_GoZIKq[nnjT+]:n|r4.5ah)DnŷЖ0^ۉ:3o= rrvQ"ݽbfKVW!Jf4Ar<~>H7ܚQ û9t"W,z&HNq61ݥtۧShkd\}[E%# \2fkt/23n&HSmgܮ97*3ǝ}{18|"6*5*Ŷ#;s9f9E "aT3C8 +B"n<=̒˔umY !mqO1u6v^ +)8;x(<@= N>Y(cK{!98*=z(cx"­ Ҹ6S[P7K#Rob_CnX2n ۫aQ~lXRԴ|<Z}FtZD.dB^ɟb0ԜyeE2$&sž/29k;mU>w{W=Ϲ tےPa$1<4 gܸb3{5+8ĥ؞1ˎ[L {yVvcODӅ* aw([2}mטx{&V,ƛYzcw=>ǽ/h!r?#6bO[c/\tfumq|%CrIywn"Hx%cM?1G=%z,^=;{Nk4:Rco 3x\wf[{=PufMӓn3LQT6o,sթ`^0t4-X28LȊb@(?bJB;Q\K@1ocۮW՘/3hHw#iL1ZZ릂=VS N n?Wepӿ[&(HSnlET7m! 6?:;,F h:դ}ܨƂ9l%t檁p +MPeB܃cɄUtFkU޶x@\**+5 /Qp>?#l]&&@ZX̋Zɶ3nn32=Sef6'åm)D-k}2n/g2.J԰}$Le7ݮq>@v_n"xE/vӨZm ܟkf + LCŌCgXͤ:uLx5ٰ3#Rs*VsO P#7VCT5U~gl]p+fcE@_s~}Ҟ>EӘ4#_#%uNJ@RTؘxƛ)/L<$y UPGg3fyyD!{Xm#㡷m3^E.ھh~FG;b$mvPP7o^k3f[VQ 1Z\hG1Ve]c N^ q +iO4MZyf:xYu쪹&|/:oc 7uNIFL=nJqo=MT|=>XVOOhL:oPQaTTB΃mg =h,S_7]bc\b& Tfɝ⊏&ϺPelS{33}-m|4캆,`NK GGY] Eng<R]w 闐:r3} s0@TscmubdC:W;=NMY0c AD2HDz݃G՘RZG%Z;P̍vi M_lm;jꞤZ#"A4{_8v."Vu_u \j +piӿ؞#N20ПP9_9K`&كXW @Dv|[ӧ:fVH. YX]31U2C2b3Tcz$@w@BũLyT3,9v$Y0tߧ dN6 ϊ2M\% 6ii@(,n[""r8 L's<+<$Pڔ7_ ',4E%g5+e ])"'=#]5x9PC =Ra%sro%ٺV4}^%fly~zo9L֦x4kxt/ +ޖf5)=G;ohuxSgĸ:g\KuBdj.eo _!@OCBRhg[q7c]G5S߳WZ +'3͙cWwfbx|&{=nhl߾٩ڠ=σ%_W.S`{K"M~`Ԙ[//)ŽLTҥ=* +_~FҼVUeL9:2η(WSѻyRYr~{WWJ!!z}ssf^~=͖2Z7>T[QhMjP@3DeVгfZG6E;HI&4؀߼7eQ}쯴)MJر+P!Oy`YʌMtySѬPgdZk똵w^ωXvrn+vU_6kSW +[:u?VPnN'C:,TSlʅկ7eev`/Ԇ;4wnN!I.L=0)hbcwqOٿ#Y&B&o?Tcs%չ{ظ]Q6Zti"V)JVdϲ x_Th0x돡áfXyu :7#:- /I6Λç%^Y{4ҮQsGOviZ:FeP$pS:(%x)|?5H1Y +ʋ%%b +Jnc6Ux9k~uNU@?Kk^U"o>)@mX3 +Y! Zb*43;6(?r( 5@0B + YYH/S@#ٽ d1Ž6{1z*믱4ڴ( gblE0AߠB?L%K + Jb;a2qwz/QW| ͚^OaՈJAw t(vcZ2wGF!GаmZ专AXE5+$g#Tm[=U!LԂyQߧ="n[m&9oݐt2ZofTnB=Ԫ'G8N{o[`VNEG='߂g.E Y/Km&ػ7.wX ЉAn&2/=go4D5CRIږH.?͟&|Ԯ˪k*$Y{sԓ (1@XlnZa1 ؛O(|Ogk`zlPh ݆o|nfYgh X X q{bZ~i;mP)B?Ph #4麴~H-M$&9 +"[X/&q1 ;Jt%K\ gp?}=Ӱw: |w,zHZq +AB0Dd^`nsh5v/8*?{l}2tv+zu6brقd'pG?e%vҥH 1j`wj TS3dןz`* JoP9h?d\gT>"U#@(KTIo䈎/"ElbCI^vv)d2)v\uM&r8Ҳ| MQ_NJ pc,-pՋ,.+t5v#+RXc/Fؖt7󏇃'x〦 Le6lP|C7m_<@}`LD/҃aXh'2WK;āKKhR4&- !5F5[JW5)TdxU,A2#cI3IХK*0K"0J.H-$٭Sv|xASJ* zӾE\MG<ȩvUmdr*vkPS +Ȱ]kHaHY vGc1w>j0ԩh{L)p3՗5"fNzU#vV8*5vP8j .ilWv'~:1Һ, Du +\9TUI-v+v?0f;F +x1 ɃwQqaeC'uaO0{ D>vn_t,tC8YM),~) + kϕ c;پt҆ۖTIC \v?+o|9tκcŹ2 [NmC ˴y.Z=|;I|kV"u}BCmnvee6 up>TJZɏ/̹=dL'f-5U CxI}kVSaQuM5>a.4HDj "EL;שUM^ f:+ +Vx$y)Ø;8xeYQjto֙+(AZ1*nЌW(GXɦ[%8r)D $Ra< ):<|W [OK(HD'$%"]&):1Yx1l/ (05L9o*H[j,LNF:Ѷv + -#<nYVF2Z&iN[ +w>5 +iUJ<%9dpHHFM~ <Я*H׮][sS˺j.jO@3l\TO_b,GL7nv܂xn^A< 3[_0g"$+5# b#%/ڣ#a~j|#".3fs2z?h8"Dz0@2RL|g2`|Hk׭w{DfP)|8Yttc QTk&LU& etȕ#F|Y3{pk^<2 .< 'Q#@#>iLFi'02<{:2~EُP `F5C#ĺIޢr+r[AbLxr<슧.wU&O^8Fej.hY8ׄ55/oǕ,&8W8HLKG^Uˮ֌pUql^ujbZ(0"ԶXe1gƩYƬH﵂'4%F'\ƒkIbU8'Xm@VC/excm/p .oᓹފI6tx-tPoqkIWr(]$s42g Ɏg;[G}ܵzoZτs~)''ZPg~+Wў)j~*ٽ9aT*l(tګ*9O\6>fJ,eq_ى^nR`W~tDQе|vѶu(|('nrvfudԿP֋&SOn_'ßK7UY]t_$[:PF׷ҡAcNqjՃġz+#:/N$.Ե$ͭ0-N!8>]Oik>*`ښ۫ +$YZ +n[-{_'7~tbqMe=l L+}GM4Cp(,8EkhR$rƐ$vi^$ <2M̮nZ/0?z&*߄*cռp"81vaE4N^ +nK=Na`P/e/pI(NxuJК[5`qXpj"k ~5=,6B_fըk#"t2'wt.^AlrH!H7Rͧ)ɩ;6}oYE UZ<WͱMpIM|M/}DV +lICDA,+Բ˖Ð8 ^Pvr,j=[D`%tK=}W;{ 6o></ w:-(!~tY#ABņGx=rT\ @ \+s{zPٍ"-w5o6҆pɭRDBZՉm ,R& K4r D) F3[!ڦ5ϵ|ݙVU=\"Zp.T%kZNp_cά-'NzRr-p50OL,pDZ0Ra*ϕMT [P* zs>NtXFsPySX\5L.T=&]9CtiYx:~{( CWtnwMYNquO ]|[RAot4 E:kVa@a]5[٩-sv<nnߴ.ĺ.mGOGuVLyN Nו$ 騿=tȨ%XttRKN,N^P!]"YVh`:t1 +W Dp`WNkl{tUv8]C@M&V46?emEv^dϵXG6[T;3(*xų]3԰z.&hT*E5@@W;W=t{.Z">HC󁦓=V;%Um/#~D#F-7itSVMʹ&rs'MH[o,c3`_&+Z,T"U]hs*6~t`hATQ-XU$;.8׏nvZ䕐 #vweE[fj$EɍuZM НZM'nGT*-OdXڜU]q nZD%`V썎QO4k!'k 񀆂 C6avi]W^iZ/*4o:omawi:@=H{Crp -_|sSzBP&z; +_npZ'[OÃѪv"|=ب<"f/kSO&. e QAiv&\7=-f}qX0[1.gضӊ"zH{Dx]bleo<,¶:Jñ;# 5æ-05 ILK_b8 'it7 S=FrcLW+0:C,F"fz)n< +)Iy. ;IѸ'Q?E3N!|Tb)1d`/ ".ȹJ-X rTb,byՖ$o(~"q>ݰB5Yݯ6_ +^B'\vYJ&-~]S}Yh4}v#Y0Sj"VȔ3L;i-QF=+ 4=D2b +XtrػC"]Q]+EcSfW|!7d#"@֯Y)g_*砃uBqC1*`7Οu~gԨJK-Fu40,3h6wo`Ό% +ZLB\8jS%-n v{T]Nm)%sBY,;ͦz7d80ѡO +vr٤qa҉(jqgq#4[~S;-wG2yihF +aR7JItSldhKetHȡFj1%Gdz/e[di =_Vi׮?Mj3 9A"\SB-ѤVX/`d~$bf$U8j:Hc8NTv?I ~̞͊P0]I?76U eVKڡabXI-CfZ]7P.ˮ)ɛyBuZ3ޣKn&ٸيo,SosK3*)){BVqU %mqAK?hbf-CK:^ oS:*0L"&B +ꟶo* yφ.pI+'HP#{{d=Kw~sy?ۙgr 9П\uxHd-ĤJAvu޿!Ncq'XZz&ciIOc4[d51s˹I# V@7PUf {]4=LM*kc,/啭j8lp̄NG۟{ֳף6?[:@O-N;ϕ@lqsDK1⮷>b_^OTR ˶UWS*#*F㡒/|#Ok8?6%qyk;2{v_^EiqIWN-k$W:Ld(78!ڼ*i@FڳsفuTd@((k?[l +Z3xRچrngiz +2'd++} i_~#s(~R7Z}.FV3pj + 8^=ܻkd[߼]*QV磪7 j_@:`3L3S~_5PYAą` )JC$/MscS|Uǯ?~ǿ$'LM@9azf>+.%3QkJX}>kĚVǢT.;]psKY"V?ar뛏:P sCG`Y1R&&٢ccB/#7d$%ti[k4(|VX[+o! +"LJppkx")Q]hawl(_>p% 7v|$20{7`Vl^ppձȣO^q4^稘է +H "ŊSQm݋2UPhp[`N|q? es>n:WtLt!csT/joUY`2I*D_By~S/pP0SLUi [1n1r3A;ALH_[ϋ6,'ݭ#GT`fN.ߢEl(9UZ 4 F+3tZH/ ҙ,lþ*{D_/ V endstream endobj 11 0 obj <>stream +8;Z\u=Ur;&$q,OD$dNl+7?5tX3(?l?bX^9tFM+CM[^J@B@Wg<j;=\EQ(5)f:$!o.%Sc+cVN.:mYS^R*6I +c*G%*Y3h6:E@NocQ]\RtUhTKYF9/3kdttAf3>W/2_,tcm+Y7]k/NBX]3qZ6>bkbuE$9([#\1%Y7Yt endstream endobj 12 0 obj [/Indexed/DeviceRGB 255 13 0 R] endobj 13 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <> endobj 14 0 obj [/View/Design] endobj 15 0 obj <>>> endobj 10 0 obj <> endobj 9 0 obj <> endobj 16 0 obj <> endobj 17 0 obj <>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 17.0 %%AI8_CreatorVersion: 20.1.0 %%For: (Abby Lindstrom) () %%Title: (DRACO_ID_vert.svg) %%CreationDate: 10/31/16 10:58 AM %%Canvassize: 16383 %%BoundingBox: 25 81 477 426 %%HiResBoundingBox: 25.0400009155273 81.7850036621094 476.735992431641 425.735009354476 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 13.0 %AI12_BuildNumber: 174 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%RGBProcessColor: 0 0 0 ([Registration]) %AI3_Cropmarks: 0 0 500 500 %AI3_TemplateBox: 250.5 249.5 250.5 249.5 %AI3_TileBox: -40 -130 540 630 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 0 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI17_Begin_Content_if_version_gt:17 1 %AI9_OpenToView: -520 754 1 1928 1104 26 0 0 -4 37 0 0 0 1 1 0 1 1 0 1 %AI17_Alternate_Content %AI9_OpenToView: -520 754 1 1928 1104 26 0 0 -4 37 0 0 0 1 1 0 1 1 0 1 %AI17_End_Versioned_Content %AI5_OpenViewLayers: 7 %%PageOrigin:-55 -147 %AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 18 0 obj <>stream +%%BoundingBox: 25 81 477 426 %%HiResBoundingBox: 25.0400009155273 81.7850036621094 476.735992431641 425.735009354476 %AI7_Thumbnail: 128 100 8 %%BeginData: 9568 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FD39FFA87D2727FD05F82727527DA8FD6FFFA852FD0FF82752FD6B %FFA827FD14F852A8FD66FFA852FD18F852FD64FF7D27FD1AF827FD62FF52 %FD1EF8A8FD5FFF52FD0AF82752A827FD12F8A8FD5DFF52FD09F852A8FFFF %A8FD06F85252FD0CF87DFD5BFF7DFD08F852A8FD04FF52F8F8F852F8F8F8 %7D7D27FD0BF8A8FD59FF7DFD08F87DFD05FFA8FD04F87D52277D7DFFA8FD %0CF8FD59FF27FD07F8A8FFFF7DA8FFFF27FD04F87DFD06FFA852FD0AF852 %FD57FF52FD07F8FFFFFF7DF8A8FFA8FD06F8FD08FFA8FD0AF87DFD55FFA8 %FD07F8A8FFFFFF5227FFFF7DF8F8F8277D7DFD04FF7DA8FFFFFF7DFD09F8 %27FD55FF27FD06F87DFD04FFF87DFFFF27FD04F8A8FD05FF7DF8527D52A8 %FD0AF87DFD53FFA8FD06F852FD04FFA8F8A8FFA8FD04F827F8A8FD05FF52 %F827A8FF7DFD09F827FD53FF52FD06F8A8FFA8FFFF7DF8FFFFA8FD04F87D %52F852FD04FFA8A8FD04FFA827FD08F87DFD52FFFD06F852FFA87DFFFF52 %27FFFF7DFD04F8A8A8F87DFD0BFFA87D27FD06F852FD51FF7DFD06F8A8FF %527DFFFF5227FFFF52FD04F852FF52F87DFD09FFA87D52A827FD06F8FD51 %FF7DFD05F827FFFFF8A8FFFF277DFFFF27FD04F852FFA8F8F87DFF7D5227 %527D7DFFFF527DA87DFD06F8A8FD50FF27FD05F852FFA8F8A8FFFF2752FF %FF27FD05F8FFFFA85227F827FD05F8527DA8FFFF52FD06F87DFD50FF27FD %05F8A8FFFFF8FFFFFFF87DFFFF2752FD04F852FD04FF52F827FD05F82727 %525227FD06F852FD50FFFD06F8A8FFA8F8A8FFFF2752FFFF277DFF5227F8 %F8272727FFFF52F87DFD0FF852FD4FFFA8FD05F827FFFFFFF8A8FFFFF87D %FFFF277DFFFFFFA8A8A87D27F8FFFF52F87D27FD0DF827FD4FFFA8FD05F8 %27FFFFA8F8A8FFFF2752FFFF2752FD08FF5227FFA8F85227FD0DF827A8FD %4EFF7DFD05F827FFFFFFF8A8FFFF277DFFFF52F8F87D7DFD06FF27FFFF7D %F852A8FD0CF827FD4FFFA8FD05F827FFFFA8277DFFFF5227FFFF7DF827F8 %F8F852FD04FF52FFFFA8F8A827FD0CF827FD4FFFA8FD05F827FFFFFF277D %FFFF5227FFFF7D27FFFFFF52F8FD08FF27F87DFF27FD0AF827FD50FFFD06 %F8A8FFFF5227FFFF7DF8FFFFA8F8FFFFFF7D27FD08FF2752FFA8FD0BF852 %FD50FF27FD05F8FFFFFF5227FFFFA827A8FFFF277DFFFFFF27FD08FF5252 %52F827FD0AF852FD50FF27FD05F87DFFFFA8F8FFFFFFF87DFFFF5227FFFF %FF7D52FD07FF27F827A8FFFD0AF87DFD50FF7DFD05F852FFFFA8F87DFFFF %5227FFFFA8F8FD04FFA8A8FD05FFA827A8FFFF7DFD0AF8A8FD50FF7DFD06 %F8FFFFFFF852FFFF7DF8A8FFFF2752FD0AFF7DF8522727FD0BF8FD52FF27 %FD05F87DFFFF7DF8FFFFFFF8A8FFFF7D27FD0AFF2727527D7DA8FD09F852 %FD52FF52FD05F827FFFFA8F8A8FFFF5227FFFFFFF87DFD08FF7DF8A8FFFF %FF7DFD09F87DFD52FFA8FD06F87DFFFF2752FFFFA8F8A8FFFF7DF8FD07FF %A8F852FD04FF27FD08F827FD54FF27FD06F8A8FF7DF8FFFFFFF852FFFFFF %2727FD05FF7DF8F827F8272727FD09F87DFD55FFFD07F8FFFFF87DFFFFA8 %F8FFFFFFA8F87DFFFFFF52F87DFFA8A87D52FD09F827FD56FF52FD06F827 %FF5227FFFFFF2727FFFFFF7DF85227F8F8F8A8FFFFFF7DFD0AF87DFD57FF %27FD07F852F87DFFFFA8F87DFFFFFF52F852FFFF52F852A852FD0AF852FD %58FF7DFD0AF8FFFFFF52F8A8FFFFFF2727FFFFFF7DFD0DF8FD5AFF7DFD09 %F827A8A8FFF852FD04FF27275252FD0DF8FD5CFF52FD0BF82727F87DFD04 %FF52FD0EF8A8FD5DFF52FD0EF8A8FFFFA8FF27FD0CF8A8FD5FFF7DFD1EF8 %A8FD61FFA827FD1AF827FD64FFA852FD17F8277DFD67FFA852FD14F87DA8 %FD6AFFA852FD0FF82752FD70FFA87D52522727F827F827277D7DFD7AFFA8 %FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFD53FFFD0CA8FD0FFFFD0FA8FD11FF %FD08A8FD12FFA87D527D527D7DA8FD12FFA87D527D527D7DA8FD09FFFD0D %F827277DA8FD0AFF27FD0EF8277DFD0EFF7DFD08F8A8FD0EFFA852FD09F8 %2752FD0DFFA852FD09F82752A8FD06FF27FD0FF82752FD09FF27FD10F852 %A8FD0CFF52FD08F852FD0DFF52FD0DF827A8FD0AFF52FD0EF87DFD05FFFD %13F87DFD07FF27FD11F827A8FD0BFFFD0AF8A8FD0BFF27FD10F87DFD08FF %27FD10F827A8FFFFFF27FD13F87DFD06FF27FD12F852FD0AFF7DFD0AF8A8 %FD0AFF27FD12F8A8FD06FF27FD12F852FFFFFFFD15F8A8FD05FF27FD13F8 %A8FD09FF27FD0AF827FD09FF27FD14F8FD05FF27FD14F852FFFF27FD05F8 %275252527D5227FD09F8FD05FF27FD05F8277D5252527D27FD07F852FD08 %FFA8FD0CF8A8FD07FF7DFD08F8527DA8A87D27FD07F852FFFFFF7DFD08F8 %527DA8A87D27FD08F8A8FFFD06F852FD06FFA827FD07F852FFFFFFA827FD %05F87DFD06FF7DFD06F827FD08FF52FD0CF87DFD06FFA827FD07F8A8FD06 %FF52FD05F827A8FFFFA827FD07F8A8FD06FF7D27FD06F827FF27FD05F852 %FD08FF52FD06F827FD04FF27FD05F852FD07FF52FD05F827FD08FF27FD05 %F85252FD05F827FD06FFA8FD07F8FD09FF52F8F8277DFD04FFA8FD07F8FD %09FFA827FD06F8A8FD06F852FD09FF27FD06F8A8FFFFFF27FD05F87DFD07 %FF52FD05F827FD07FFA8FD06F87DA8FD06F87DFD05FF27FD06F87DFD0AFF %52A8FD06FF27FD06F87DFD0AFF7DFD06F85227FD05F852FD09FFA8FD06F8 %52FFFFFF27FD05F87DFD07FFFD06F827FD07FF52FD06F8FFFF27FD05F852 %FD05FF27FD05F827FD13FF27FD05F827FD0CFFFD06F827FD06F852FD09FF %A8FD06F852FFFFFF27FD05F852A8A87DA87D7DFD07F852FD06FFA8FD06F8 %52FFFF27FD06F8FD04FFA8FD06F852FD13FFFD06F852FD0CFF52FD06F827 %FD05F852FD0AFF27FD05F827FFFFFF27FD13F87DFD06FFA8FD06F87DFFFF %A8FD06F87DFFFFFFA827FD05F87DFD12FFA8FD06F87DFD0CFF52FD0CF852 %FD0AFF27FD05F827FFFFFF27FD12F827FD07FF27FD06F8FFFFFFA827FD05 %F852FFFFFFA8FD06F87DFD12FFA8FD06F87DFD0CFF7DFD06F827FD05F852 %FD0AFFFD06F852FFFFFF27FD12F8A8FD06FFA8FD06F852FD04FF27FD06F8 %FFFFFFA8FD06F87DFD12FFA8FD06F87DFD0CFF52FD0CF827FD09FFA8FD06 %F852FFFFA827FD11F8A8FD07FF7DFD06F87DFD04FFA8FD06F852FFFFFFFD %06F827FD13FFFD06F827FD0CFF27FD06F827FD05F852FD09FF52FD06F87D %FFFFFF27FD0FF852FD09FF27FD06F87D527D527D5227FD05F827FFFFFF27 %FD05F827FD13FF27FD05F827A8FD0BFFFD06F827FD06F852FD08FFA8FD07 %F8A8FFFFFF27FD05F8527D7D52FD06F87DFD08FFA8FD14F8A8FFFF52FD06 %F852FD09FFA8F852A8FD05FF52FD06F852FD0AFF52FD06F87D27FD05F852 %FD07FFA8FD07F852FD04FF27FD05F87DFFFFFF27FD06F8FD08FF7DFD14F8 %52FFFFA8FD07F87DFD08FF27F8F8F852A8FFFFFFA8FD07F87DFD08FF7DFD %07F8A8FD06F852FFA8FFFFFF7D52FD08F87DFD04FF27FD05F87DFFFFFF7D %FD06F827FD07FFFD15F827FFFFFF27FD07F852A8FD04FFA827FD06F852FF %FFFF27FD07F852A8FD05FF52FD07F827FF27FD05F827F8272727FD0AF852 %FD05FF27FD05F852FD04FF27FD06F8A8FD05FF7DFD16F8A8FFFFA8FD08F8 %27277D5252FD08F87DFFFFFFA8FD08F827527D5252FD09F8FFFFFD15F8FD %06FF27FD05F87DFD04FF7DFD06F827FD05FF52FD16F827FFFFFF52FD13F8 %52FD05FF52FD14F87DFFFF27FD12F827FD07FF27FD05F852FD05FFFD07F8 %A8FD04FFFD07F8A8A8A87DA8A8A87DA87DFD06F827A8FFFFFF52FD11F827 %FD07FF52FD12F87DFFFFFFFD12F827FD07FFA827FD05F87DFD05FF7DFD07 %F8FFFFFF52FD06F827FD0AFF27FD06F87DFD04FF52FD0FF827FD09FF52FD %10F87DFD04FF27FD0FF852A8FD09FF27FD05F852FD06FF27FD06F87DFFFF %27FD06F852FD0AFF7DFD06F827FD05FFA852FD0BF82752FD0BFFA852FD0C %F827FD06FFFD0D27527DFD0CFF52FD0427F87DFD06FF7DFD062752FFFFFD %0727A8FD0AFFA8FD0727A8FD06FFA85227FD06F82752A8FD0EFFA85227FD %06F82752A8FD5EFFFD05A8FD15FFFD05A8FDFCFFFDFCFFFD30FFA8FD07FF %A8FD37FFA8FD22FF7D7DA8FFFFFFA8A87DA8FD07FFA87DA87DFD05FFA8A8 %A8FFFFA87DA87DA8A8FFFFFF7DFD09FFA87D7DFD05FF7D7DA8FFFFFFA8A8 %A8FFFFFF7DFFFFFF7DA87DFFFFFFA8A87DA8A8FFFFFF7DA87DA8A8FFFFA8 %7DA8FD04FF7D7DA8FFFFFF7DFD04FFA87DA8FD04FF7DFFFFFF7DFFFF27F8 %F8F827FFA8FD04F827A8FD05FF27FD04F8A8FFFFFF52F852FFFF27FD04F8 %7DFFFFF8F852FD07FF52FD04F8A8FFA8FD04F852FFFF52F827FFFF27F852 %FF7DFD04F87DFF7DFD04F87DFF7DFD04F87DFF7DF8F8F827FFFF27F8F8F8 %52FF7DF8A8FFA827F8F8F852FFFF7DF827FFFFF852FF7D7DFF27F8FFFFF8 %52FF7DF852FD05FF2727FFA827F8FFFFFFF827F8FFFFFFA82727FFA8FF7D %F8F827FD06FF7DF852FF7D27A8FF27F8A8FF52F87DFF52F8F8FFA8F8F87D %FF7DF8A8FF27F8FF7DF8A8FF2727FFA8F87DA8FFFFFFF827FFA87DFF7DF8 %52FF7DA8FFA8F8A8FF52F8A8FF7DF87DFF7DF8F87DFFF87DFFFFA827F852 %FFA8F852FFFF52F8FD05FF2727FFFF7DF87DFF52F87DF852FFFFFFF852FF %FFFF52F8A8F87DFD05FF27F8FD05FFA8F852FFFFFFF852FF7DF8F85252F8 %F852FF7DF852A8F827FF7DF8A87DF8F8FF7DF8272727A8FF27F82752FFFF %A8F8F8277DFFFF7DF8A8FFF852FFFFFF2727FF7DF8F8F8A8F852FFFF7D27 %F852FFFFF87DFFFF52F8FD05FF2727FFFFA8F8A8FF2727FF2727FFFFFF27 %52FFFFFFF852FFF827FD05FF2727FD06FFF87DFFFFFFF827FF52275227F8 %7DF87DFF7DF8F8F827A8FF7DFD04F8A8FFA8F8272752A8FFFF7D27F8F8FF %FFFF5227F852FFA8F8FFFFF852FFFFFF2727FF7DF8A8F827F87DFF7DA8FF %52F8FFFFF852FF7DF827FD05FF2727FFFFF8F8A8A8FD05F8A8FFFFF852FF %FF7DFD05F8A8FD04FF7DF87DFFA827A8FF27F8FFFF7DF87DFF52F8A8F8F8 %A8F852FF7DF87DFD04FF7DF8A8F827FFFF7DF87DFD04FF7DA8FF52F87DFF %52FFFF27F8FF7DF8A8FF27F8A8FF7DF852FF7DF8A8A8F8F852FF27F827F8 %27FFFFFD04F827FD06FF27F827F8F87DFF27F87DA87DF852FFFF2727FFFF %27F87D7D7DF87DFD05FF52F827F8F8A8FF7DF8F827F852FFFF52F8FF2727 %FFF852FF7DF8FD05FF7DF8FFA8F87DFFA8F827F8F87DFFFD04F827FFA8F8 %F827F852FFA8F8A8FFA8FD04F827FFFF7DF8FFFF52F87DFFA87D527DA8FF %A8FD047DFD07FFFD047DA8FFFF7D7DFFFFFF7DA8FFFF7DA8FFFF7DA8FFFF %FF7D7DFD06FF7D527DA8FFFFFFA87D527DFFFFFFA87DFFA8A8FF7DA8FFA8 %7DA8FD04FFA87DFFFF7D7DFFA8FD047DA8FFFF7D5252FFFFFFA87D527DFF %FFA87DA8FFFFFF52527DFFFFFFA87DA8FFA87DA8FF %%EndData endstream endobj 19 0 obj <>stream +%AI12_CompressedDatax}w_*˲|PQ 朳,ezRLO {}g Օ;:o;XtkTroA\dZhk_{5o~^N +\'+vfOٮ۝l2GWA[_ޠ#k MṢy>,Zr!~"j"vIIP^@8, U9NTt V +( "AsOr6ngN:N,xRM7ZVɯfaU?~7m*+imAV_`0G_$K8}Κ:joƳw7 lBDT^y^F" 9il< +zKc$Xbj́1}qh~U[䝿UwZKp|T"6 0/G׏2`iѾܐeK}%yBjwm^0l8wWu tXWn΀N{M@r^a%ՠ^*$5rAx z_t?Ue8ȁ<%^KsK +̼FDEhu>gg^v yk yhvۿ:! A5Ƴ$yrV ~QuPmvM^~5Oo7{ӨpV'OlGWT ,CϚ9IZF]na;j:]Y.V]Ȳ/xRtD.F]@iýԣUΨq&o핪VW~6kްtZvیv?3ߌA5d7##a}ڧmcM=ޞ@~4@_.!VWib +SPOz#$)AO3_^ZoA,k`HoK'bZW3v^Mc 2SZ 1b"V#G&F_+6#qzaJUP%/`,?X٠jbQ q(E +gl0d貮2>5g陀6v"fO,Oʷ;1?qf?=+6۝N4;0EY`xj @T`.M:}qDꢀSz U0ީIcg.IYy $GﶪYd.!)ζ._ph:FcN%O}|-K|͸Չm-4y>iȾ]6YQYX/i7z5W$[}o?n'j߭$?zzo7* QUk}kw6),<4ݰH;is'nHͰbNb8 +·>ɯvю~` 9Z{^)|, =X}DVU[MSԻ͂-8[A'yQ=p,6qٵiE^*N|ؓ0d YofpOA vO,3$@cvJ&M9խ +yH50Г+Q,5Z="߀QT,NƂXP5)RX+{46܃-ݐ|mU{ ށ~cP C?~% 4uqo)Mm9UNlz=HFD +/z~jvA`9 haZ=wG3{zLfgX <)*ő5]CҶsDAU0Qta`A) 'r0.d eO՚ʹO|HY@ؕaeLj{Ln #Ʃ]z!t0Wp@| R ^ -UV%xO+ $KIa@uL]|70AWp(1pjMأšL6P$:ͳy٬}Ʃq. +emu,#eejQ@yAC'ShQYNF81A_4sHQp0!$YS%f0qWa*xܨ7I'J<-K3H:0ZǍmSYp>ETI%f/ov lw7A@ZuD:Azӫ7~,tǖ<8Y~/eg-X_$m2]*ImpC|j+[G ⏢*_;te6?x߰+?|/p\s +0hn|NlΩ̾^bZ 9/fD:ǕDN໊:6ݏczׯ4eX 8Ifn|on~Ȉjn@VB V(AP7?n=;zZ^׺ڟ`2Y&aXJ +kiDޫ~ `x| PYyO qv[f?RILOԂ> +f୉ )F:X36XZ62kS{4y.8]U2 "$z˅nWڶpx= T/:1JG\-UJ\Y@$D?;lĚcƒZ) aA$b[()!`:֓H^K9ojW@&,eUİncXaCB/,A3H>U_|Fa&{|x 0Āa3@_o7͏6Y{{-zMЅu|NwUpb c BQ (Xg0`]@) 0<44)!(} 1dIZ>7`̘HiQv~.\dl==={&"4G~3MGWmkcTaPߟA#JvM=!Ee֋F4l% #=:exy zzo\[JH̘qq8w Q9 KdFi&pfqRv0-@\d(dմ̭2HFJe +,0/I4Z6* 3tWa.ʲ'a +,GZ}rO(n܉A&ϴ׮Kn:jlG?fu(6P@%Q0MTɺFX,v@* _0ڮW{a+JD vnXNB41f;ݷu&0xF`JO$]{Ҍ3'Rɿ?dʮj>.뜬glrL.$H&᯻?a kJ6GtuW0䠃M&V&L2P~L^N3Fom !O_x:H!X5{dy 10zYE30l5ZFC_EAlYo?tKk:a•lwdUob^w/5ț e܉,YR}P iφ%/|Oę'ÿ+辬Ÿ-_/m TnwVȅG'y9<@Onηʤ̓>~1?Y 8yL4?E#0|gB(PӁSo\9} q* z |B&(ܺ6nދ\1wm|D$HˢDW/}kobZݯOڅʊ{k|q"NֿVSٓ=لGo +p2t|WNc+gHr=BW6NmMԔa5V騷"Wwr{R"뭯o-uO6z[tW~_Uֶj6{F`̘\'n^Sy-r%JvRKu9m~Rv&-]pE٘9t+FȮkNdxԇa/ =Ux s뻩yb_M;eٕ]9[>ƁwsҌTJ4t+_Nz?NKE5/:k|\$=tuf0: +s'ҩ.T\X TV~N'r}4Tkl(Ӆ#8׽pf}`^:U][7;=[XtH\;Nȕ+;WQdv: T-\ &ҞnaUE˹>3EՄŋয়՗c0P |(Za=%SfOgj{ok{{}鯅u|,{\-1ߔsxz~/>ל>_Թκ{OnsSc_a+rAZ |Zk_cl>5tg@ؘ1o{ڢ5̊i꼿a>-V\wzNxvqn2YO76OQa)XBf8gkVyC\3a0o)?} +[%T([uZ3hHŶ%7{3Y|"kFqSXk/y7D ko\{ςlAw'tU -6'PwN|y +sr:M IF Kg )6:\=^6}'b T ClsRLj)yg1T?w k +[ ׁ뇞xx(4YfSh]WC+y[OLYO?xOɘ9 \Pk9,Fx =(jd0.s\}$&\}VXȒKR qta4-F[WAbo"FG1Ŷn9UK t2AN/ ] +6쥋~6k~YݳIe{ZR'p'f4Eua75m u]jֽBbX{rl3ױas`cfj\}3Q6lx;$Yj9P&;64܋ +^`(]HD:.Nܶh1hxG87465 Ӣ/Pl!v`p`%<=LZc8xHQ~lpatQCA}1D:r~繿?MS| Ό]BP Yn,t\ѥ P̤'$Y۩>pWP6hj L͐p76[-n] C:ƜE>:F7=hahHD<ymQb`H۔c1 t'mJ:ty:|4APܸV)"B rUcM-8D:T:9#йCCkB) +<peAyDze7 x,nV-8+-'my|Y]z vƦoŦ7LFITwvnJ/.œV7Z1,ؐv&ةpZdؘ{0кSKY")cƌ{HWbcBa=@Tn,b&ܡIW.J4@OĺD[swדH4ODv$ƥJPއuD#NDKogWN~v)29ǽ`#SB!J1,Dx|qͽ;vnBh56YK1yIMl[㺟 {4݌K͓4PV\=QO+A*K=h3;&@+,Lr^m9'_Vg.)#y|wӱܺ0h۸u"F"O?>yHO p]OvbaZ3}t ~Ч U6|o$jL<,' ={ YCw,vn$KX@ݑbX,v.a% ,.R k7x%Ilr%R+>T*y$'MؾsGd E2PmEٻiqnh +D\*A{|cMɷ.5$'>b>[L}R/H!*-+vɬ#L..N SW!-' jiTAgzЅWЙՂ1;+XՂЅWYgwLZC^AԾMVC^Arl5t^·fW^CWet:2U-Tq!} iU?BA}dׯD0m1v9* {Wr4O Nce#b,(ygTꙸUQߘrIM|DMx9{{. l"J<HQP[3B\\'-n!,.ȯ FGTi,kOaÄ" I_&g +_xjʃQJ(9(<%u3Y5mA>ǹL{8eS'cXq:$8vmuA1$9V6RD&N"^LDdƌȸ% 878\9F4B)GGdq&n#M1!9d,s\̔K#{P7X>C 3(č=dtܙ*1P2JGNF-g&1w)B|,8L(]W7aC̺!m6hRz1^ah4ΛwFڔFo>Y7y}%M{5.fńpv"nꑀz+RǬcW N.ZZNζ/ՈQ8z8 V:fn9A!KllҜHGtbDFU|,lẁ?AbjtҤfsɓR'T*0!o,Rǰ.8 6j3Z^&4챈Ɇ7Z1hEllZ]„Y8b5^iF`9+@+쎒0h( ~$Hߞ#gpLv3CͨK c#-VZyeQZyg FHNE4*RiTb4*R+RoEj1[>ڕ22͆yޅǵgNR +b/ \9q-cclڥp1 K5I)/#bRpÐ\D'A»32z]-$1lX'uNi& +Os1@J✯6kW~N|`u;{T:i!1׀\~ۺgÝ>RZ?,J \g^~mn)WBT.%]K[srWcԝonΗEwJ?SʟT'.®?Si]mWՠNB+v:թ>\[WM۷`}|b7inu;NQOvaugav+V}|GzP]#.ӝ]"x-uz#%`W{ɤe!Wb(=a/fi#aZ[4,M*6/Ml]Gw*jvOb}{d7ɱ_CWN&9B4#]a1nqy)B.f\:lm k lH/L2$Ox~mD\C$өcл0y5wgtuXtN.xrtArtEcWӱ%OXM2Z:7OUKǒ0UӱԫXtԪLUKgeNUKaUMZ]j5{Wtt!%L~̓'c҅[JTӱJXt5] M!O c6QMcTӱjݷiVӱj7MRMj_32i5{$fdj:H6q5.^1X+rFttZx~e :b/[MǚLC +qC*R c~ܣ"k*bƞ?QN?:u1bߛy_]ܚAn;.ʃpNUnQdq[鿂6R8O申AR6$'Kd= szףGq`\s,v0cc#^s;v15w6]tL)蚻ǽsJnkoHS;KW^t<.pÉ#s5v뗱cT%bIMJɭe'. <!ךҍWTLO\{J* [Q'LYnP9nd[K|FaGL +RF?z.9ۆtV1P̄eDZUq"r4ГUu3K,B}Hs3RVؐQ1eqӄG\#U +e1WRߍo[ɤj8Ww *8Y?F! ~MӽHvy.he&{#TbcǝorƢjyFXhعiGS |H7Qe*5. +?v  +0d9^<9V`؃F=f6T*5szV'KWƯ[G[^i?+|F_/#]ut.3$|)群R|)(Q/\bڥ|LK).ۙ&llqEVφQ^Щe&S:P<j*7B}ıcέ~[̦4̺oJѳ+F/V4,n^; ׏}_sbIc]=6ʽ~+T6rwVqXkYQſo[ƺodǾotZqdwEKi^bD'/<Ɉ^?*] Su_~슡 7ҦSiʩ=o 7q^V"}_~!{|=4n#rl +H†X6*kVr,^ɬŹo{o>q{߸[ǮL^?V0mubPsp_~kb['oSƾS>QYM^ o7iΕu_@8L13U&/r5~1bh wۍ w۽\9~,̄^~^?ae{eG6?ѽ~(g7~;6&=.oprls_B@ 8g{! b=J)2Cr0jxb;Qi%Id.zZ_R24̮2n-V8ኧ ^/zg +A*x2TRs.Nk]I}Tcgz1.lls{'[?m%TmsN[\?_\jqpX]mz~y~^5N䟛LVV*8L[wF{m$u{0'fvsQ<5Ғ˛T!>~nr&W>*jܮ2^_~Ͼ(}.ʭH~{^6ϲw}]ե+GVbk '9|Ӌ[G,dtt8 +g8yZk.1mSu%=CSåtjmRڪ\]F~; }`jg%'jƓ ]Io bu%]*;r}fyN9)g6ՃbRgvn7@[{}usHo)whjָ@3T,f\9JȬ;G~鞵 +Xd8}xN\q\ׁ#‚ϐ1DmWu׵%c +kbeG8֠=.W^J+}~i5z郪 G?8yڰ O=E̻|D?ߐߛP%{H m\n#=_2@js)@"ym EZks9"sX]LӜKh_Q+ +nx_l +[g_GԥC@UW^euY x~f-pP?pVCeԬyx"Zu%Q/o +y um"[hfMW%ڠDd4ZhX6LmZ _s;+~ [5Q߮;S nmr;bZJM6ԅ n܀\,tYZfwճSE6*E|03}=\oSfx Ʈd Y 7?H1"멏Oq-|™"DFg\xy3O +1챥S7UXu>z|>>@ [d֜!U?|f_ۭv-WXԛVɁY\cbv4R VԐDŹA9Y,v8hdŹ-kC<%:Lav@IeOTV?۩%rb|ͮ,n^SE*w>3O/S-qSKw{lZJ(nlC`6r3v*? IDNmkS|ۼYߺZ)?* 23m.+b:?ӝ%R2߃~6;{UYK˿2WO˽,1'rtc˿滳bHkvM݃/%4[ 9QmdBd/O6+eY~'=g wߴ.n<} oү(z֯_w<^)-wW:wq[5evbsydwΚVqRn&/J&(rBA}YJ c>Oŝx"=#'&4?1'>8\']\]M-tP}`L-e7A.n/Z%m@ϟm7pPs.#! '3{|#xilW^W736-a"\QHhg464"(}_1(8g]av3Wmqy z NGp)+2i(-BHMf$s5,/_MLc6F1WxN\Xi ݟl-uͭI: ykOy;u]=ʭ9m{ }V^wighZ]( 5HwKh!9yq$~p xD<,^_norz \9S(e=D1'uiq 6-h"=!z0 +6==;ǐa k…72?4g#WatB]1g;VorfnqKVwx(/p}W{ޗ3] +#Md;7G/.^~ *"}u:~E&vM">9}KLvH dSxk@Z%Y&eѴcG +^to$xl˻6k`H5Nf"LԖ!kUl_cY\Z^'͏}wK\;;xH}MI$ TJ< X=/ը8M-^xQ ,NOc8&sQ"1|~n7 ݽmev'05!+yu}D=D;LnbX\2" ?7ƺL= +`h,4qEc{?m\^&Azj%=ԁ^?rLD˳=_0QSQD-V R#u\2!FS;DTȽޑ,>kAɛyIxFӖg6CjoBU6^}$fEORS q=C*;ȩLrG5H;O3*6.~hQ8,?: zXߨJ]KyHR +k) 􃏵_TI,&:DO2Qv ]& + NV9 gTZube!m m[`Vl*%lc{|m|·G<+Wr/+:J*6b +@p~[B;ʼnV8:QWztHoYp2iQ!%!;Y]+6P_R͇} ӕYZn] V_Ofu&P[:kȨ^foٻO,U(ۏ$^m4r-\;Y;qus0T2e"i+ח42 dht#%x5++ğ9eTMr!Ab3gs&M[c%gݣ"'nL*GNۂ-2PuOj)^ [il'+>_JѸj3(wjF{\N.K\n:F\&Tà3>Õ'`q_{k/~ݛEH}e"Fg +pʩRdʌwEZ~0d/g~] K_$_ysm\W2DzUJkփcD= փ"|N)o?xkί4vKK +EORkƒ (T޸N׳MePx9j~#jM'=),iet3_IE>9=R@A9yz!r:^H#Jr&<%-vtp3[t#gs]M+ ~}-eo X^g-â*~J,%mlq~> fha]`ޫ.&̥ -1cR_酧V]X8Z7U큾 /)մ։ +x*}*6Q"J?Ƒ[lT3Ief>UyS1jcȃbv}EWގӺa̿U`7׳bGwܬ+\yDѲx\Vse ewf)7g(P@n\t#9N5 t!AwߵhY6]^Sqs*m,b?(-sD{^mM/TΖ~y7(`si9G9s:PlV]Nx+a֐¹\R^L{\bh/KY@٨%r߆i}Ӧ6u\Nsd/afqsk;C5ct.exl5voC~ѹvmot^7:2ySq(llR?:M\MXex?& T^z<[gk&LeR%`NB\ {_4YƲA4UĦixduXph,#h,DcK#OfBb\Gi;o6]9F4UFRS#/eZ_#@%8h~-yO1Xm1̧%#|ҺWR>R|ŃM|NrsOFxcaؤ+ɉ?'zO6L=E(GX2&d|- +0׊ɋPB'(e('!~QY7P#qN/GTs*"}w7sTy^==吾sfh9 ~r$h}gy'.Q7.݁pvɁuh$B`);WȚ}9:vzZ¸c Z'|uQ) i/hv זK[+oOuվ5“ۏ/eZSg%ţ%* +i/Sn:sc%2aA#$ D> !F+ju]@úiA< +T|}H2q]#X]{]iqX$) 0-2Iv9R|7W:ڬ<|ʿՍ;Ɉ-2H LϓP*f3>]YǺ:<ؕu+veJdTvejD뉕Dw(_wuzw2N/v>i|'yAK + _d=!I>^BhkÇTJTQ/ D&L [bD5 ^t`%6^P '*H,ĉd}0B#{L*J,0}vhcAx5Dl:> @H6 q&Lg2H<^z6q E8|~a(,#xf{~蘬_~?V^v$0cDӉp`C —$015--vr/7G &/%3ZT4%L!HB&fA0A&#!b @Lh1ㅀaŀAGSA:, lZqU7A)ME?epOYx 22a0@ +4v[ՈG#㬀;Oєn3'R0"IZ"$(x`'0Y}h_C 5 +E`l-?FbF!/Ρ * $d l°,܏l0 U ;QW%>_aB t񀋱4,y,PA.}Dt D@NPGrZ4̘f!w`gH;aaEЁ34jM DI uXjb\5NsI#]*)T #Nx@r! m: `$# ؕ.hG0ECxM bEӴ!qHt8 M  Ɓm"DLI\D\|%R;CcFc !J1pg5|F̀Q 卉IEZLYc`k`)~Rl)Зtp s0|rs # 22=gt ʓ/xHv +c >0v-v` +>ʀD]~? +jE K`]| `|`7B"g)!K1pg1XeT+`dOľQ3X \Hb Ɋkhj* + ~]PU' јڎR]BSX #qs9R26T4@Vi9!xдFE4<fBX0`8聓hÀ""tu`A{H9Z7^[&# o<@ѠA֧d\w0a4M+$0 vp {`(m ĿR2 +(:\Ea]aSGaQE$v&5p \Fg*o=c.i~2*Ɔӕ$u ;QԂ#f8 iZ`mpn q4-"ql6wYLhnVETP J An<_3%ct Fp0H. 'n:+n4lAn6)шfDJ5+:xI f|5 _;)Xno^Fοv$pE3)7('E4B>z ` +z\^b+XOCɖ)za.08 HKSA!BP /+V<(nŊ hkn@xFDćƙQB\;s.DI6tFj3SD J sېgF2ĻKA*i>i`M0|@:PVEuY|-nͧ9'F=%|8ţQp +C`@:pv uLijY4σI"hkw$z;=f, HuЙ&xF˿e/Gd3[H "CCѿZJc{OV_V;9MN*w0mar 7 ybI)R!9X6հThgp2bdI6c~tP{BEK}0"g8D|0"qh[DIRx | @Zm~Ɂ=xVbQ2<2웏DDq̑k` @m)cC[F`3qgVq[@V)1w#~$#+?gV ެMWK/{iŪ0 +BL-Zn@qU b7Ird, +bAQʆ +&ML-櫊vxVqw,p*JdN3Tf܂ H#w Gc'H4Mzqv8"ǁar4J,G NQ=MтFzQ@ֲ&KTS3a#a=`Ģؚs%sT9igd%pϷ"d[9Q`|?@ 3:AUBF_b lj<q!R}ŀaG X 1^q``RnlB_A9 X !*,^t5Ɂ!b1.:8)V2dElbH$+ Zc]z!0F( +f[Sol] /L-ndf@z!;  #PHtJ +taadd. (=BNQqxUv?}ހiQ3Rmcߒ&Jsf$JRj@Vɠ QUA:jZ'HF?.y,"-$i(LdFbE,Z'@ܢImeIiٝ8K"NX\+X_'2و@ދW5^4P AIPA qݼ0+)sq!N"3T+HNA%2PXTK1F0HY2v7$P& 1r"JSiVzSh?%TeA ?@ SL;ъ)CLyab +FD !!,1)hs^jPe}72ZbvU*zab%tD2.R + @U_r`lL)g6`#]M`Xwq,yE-|O" +T-&SJ+| ( ٧*CDOXKM:CDk /@*`YٌQrdl㮐c%zaF>.hW^0 0z<$8IF^!SiJ{vH$( c2l"@`jJF+ + +WDг`}0mH|tc +oq#ՇYH".1X19>מDJ6黎1m*u" KQ2Z:a +0|km}>M cD˙xpIL1L8YK +a5U@L0,$s80,(cNxta9WY?ςaΈDk5H<-+Kx$l8WR%} +־@&h +J`7Hp\ubMhRMG)dD`3̩V42ec֐Γ[7ƣETV$9ư>mL1!@5-hrv G (vã #F$0x:xRڽI@nme@!@ST5+Kf+OIGkǽ 2GF +!jsU^~D 805( jjJ 8 Qm]-J +9Kދ6zQ\w8sN4̎c!uE hEcEA~$kָ-CuKDUR%wILVu ٛpX JP&2[ufC(6~DD V="& +P3 A4~d=ZȃSh@0!x:Xf·`K3$ +k@IdDչI<ƛdeaCC4* +!8, TSN l/ۘ%9dY' ,#y< .(x({<`WʔHJ4FuvNXA(b%tS+9g }pn+"Y<7a()zm +DfB 1Ru!  +o]E#*L#bzuLg+#.!dj #J$7T AӀjSe"] %8 @n4.@G"bf,#UՌ8^)ߚ@JR`x `?0u`sE%d0_YNqM71WۻlǁO7(cܪZZe_i>yzl# 3(z dDCd?CHvGuZ\'T#l\2'Dm~l vc/]Ǣf߀/$(͝x XoM N [v +Gm;ՕcMߎ#f:a‰er%p,8u\c'9$>'V垜 ld䛾tPFhX.$!ORUh?>=1", )_,{&OA\*V0R`(?adu:,$DZ[ɠvUtd9JX޺=IƮ5);\ ȜqX_C1enDflv|G@dሐ=ٵ}ytu>!gaKzU^%&"k0Y X(u%EVeb[ow Zٔ*!(8f߫2-1Q4EWCxiH0l_VdK{#6uVE9LΘ3˃aoĎ83K9ܺkl+$#(ʊ~9w 0k [i:;qB0ƹj: A6!DVLy2Y{mv-By8}vJj⧌痆DG *6:G7vx7r^5ƪX԰J&(o%VfCHZMGʥShsX6Y#XKˡ}ɳ rS(CA+I 1NWv?Z 6QY/Az؂Pm;(.yꇑk)ʆyQ[z1ޑy3j",+ `\޺mb,Po3)i'♇]]rJO09Rޅ#0h́b?#vYx +T=~m-LC,#l57X Qq7C4ʶLDƨ +sPaiQ+ RZ)Y9mk&lӎv,;(5 ҝ\^qM SـM#/q +cx̟.:?TMͅ)DZy~ŹxC>JiKKM%nP%A/80+z)Pdjmo^9'FzlHrN8֬<>nb vKr@8`ٷK xm8Tem+famX4MD2}" D8_6S\5R]ao>xb(ݓ\ .Q5:"I0Z4p.o#.ڳikoRDΤ~xiuOGBŹ `jLr= |@ĉu!$P1eKU {E+D۲BNB<|u +֞.9loyݺg\"$; N|Sh@d`/l:,$%|61rlalK0GӃ!J8=p'Q`#h]131X?KCTݶ|IޣB\` [ 47Cj#v UI"sA$b#r/ v&aSy7^201wݜ.TdH, C@C`y;T0kt`˅ܨm0vj;+pQN02fuQU/`wÉ`%*HH5@fzNm)NR(C +ٿ)04MnP4BⰀM;}gR#h`͔sĢr&'Ƴr1 ,) 4>ȇԲW:+c8DJ=#V^$OD(Nե .9,̓1Eq,IfP̊KI"vdQOGb?AtI 91l'HDBu3Dk>5|(46VD[&q]\Sv:b0{(rδ&pCҴB2 hty$xl' *!㍢ӫ cK~h#t<Gh#`R Dfxx4{Py,6blHl#4q,w=y)V +s ޵xSЕzH:jIex V2X$S[j.q6~ +`ϭz?g0}o„d_)_zc<>f!"݃03dfn}2"!SeΓ R$!qNeR'J[B[V +@2S6/Hz=HFd-;2":|%~ έ]=jx=N:?5IƟ~@{kKJeJ§aoYSAF:G19gYD߷_+J$q{ 37Vo>!4`5M &I(77;S&+_vOm1ρ{l#Ю?^Cۀxt3#q "B NUzwG1͎vFܒIx:N\Yn95 +X6D +}Wo"ԹuPÖ33P'hkk}ni,?_R QȊvު @ Ա9\LllXK¨F@ NeWKR$Rڅޅiz>3Ld\V"p +*yC(~ߜpQaP:]nd\5&o8]0FVɛ[XCIDX%fVţ:1?1 GU>; 2Z+")w 5} n\?k!g- AN+L@$!M;CGʼn%8v;*4lo$e dZdecvng +׽s&ψU DVνx# 5nq1fo܅2K༪Ya 'FWdھuPŪJфI58.PK A?2èsilv$qi~up˧&@c${bu",P(uH\Qly2nͧ}Ka Ƕ ʊa}zcqԥk`sB#Ş >yxkkQp*y~6棵/Ҥ {'Y< j i C2Zc~޼;,bLH=A{7(.+=qR ph ̛+(@t.KDmd\|0סQh4EρpYQВ/rDƀr8a-zl3׻HS2B1ppe1"#_<H|o"C~t~qt42J d$  h (]{i"↴HbP^IzF_ T UZEPm\RGF`Y[b㈘Zc[Y"nIҕM|ŏT!1ᰯ;xGyj`XtmF' 7\!, U,4l9IKxlBc=;Ot="݃Fh| +iڷpo/9.@")QU, b,/' QĂ%Kby^ÂN$Bda_đ)W +Ib}y>"$}zFې +2vv VT;Aa P#w {νXܰA[>'${7WaFI/o`7v]*r=b{Q?.5,Ck)661A^ JN Dưg0iR:Dt3XDqT[/dʒF@߀zE#QW1R:e.X`o+akj˦`MB~naHQ{ۧrV$&a@ܨҭ"#Co:B V-q٦xfC щ3TO?TJPf-x +>\EPҠ #UX[ޤ`E!@0}065){9퉽w.%#Œ= +l[E +$Mj_@-xHȕ3V4SWQ.fHL.gYb4^ d*y^JQI$s;ΠnÃmBJug,+^əi"hv֛n\KH!7eyVp"eVr^ ڬ٘ kȺm+A032j_?M!"Iڢ& *:czXN|ԈKl,93PEjbD&9pJeY0eXfC B EvyC@ .6晴DhSkpCdgN@*_4*ڨ\k )g! ] &gT"pXLƧR 5GILH2ߒ]7BFf4qDdp?Z5>4w:qXe3 ;]0%Jd\rݩt^zmzb:Ig4)$WnWݾL6~M(G:qupE9y珓m6N`mR99\snP5$f~߯mq@`?ɿo;6l_z-6BwL +iȍ}]m-_Яy0 Ih2- $k%M.8ݳ(Mדt_kHGORqg~Sui1& 74O+@T Yy\=Za)5"HN`+|Q]&L:y|U [=,?BpoOBD 󭠶D<)Lh=\@zojdx^e8ly'P-,jC]Z$(&d0VJXb0@DG\mTZ|t := +HTH(;~+<•'l""P9k8P*7{csZ~+AR s2w\ +Iv^ ު%1$7N~gL@hXxsY@FtW`ڦxR}s E"4KiZdPEuj t,c) ⋋'x@1F`_92K|9ɌbXFdА0 FQЄ\A +,N}jO=z=76ڔϞ*&`Bc \7~$' 8' TWZld[pR6ABB4D5qWPͅdx2zgS0gO'DʣWUź + 6AB;(*Y[/'~o.R0(e k@lסFy"ܽna){ko槸5c~cJ1C ;`{:5) swEBޓˉ+(C{p`B2kPk*$viW䴳e,~0{YI)o7 RQMH@ û,J`G#0S !-HB;Po/$K;ɹLYaJ\)呢b*ޢy5i-7te"1f C,*hS5O[S8l1#=H<)f +%𦌗r1;XoO"T}-al!`\Д[0~o>QќQ$1lu/\d㦃o3PR#vK1P~!&{6ђ4O8m Y zIU"cmJ atW}‚-x PF8%[F!$t,5vb teOJV\J{n) $UV4#┙yl9K?i1;lh5{'N|qb~0J&$,B:- q9,L Sm@>{7P +XumT؛lY^ϩCN5[TOd)-3(Ad8W2EG!BwDD{" YĈ,Tѐ7[rqCD pθv2pb `k# &M@ƛu8FX;;):"ŝUP *j("h)QN$L|*ۭl9,H,ju``aId=Hp.¹t6;#ֱc$1Ex1281׶nFLu?@"_;p /儴pDPkЉB1jϘn~ub +Q[bxැq([tX'24=å kdm "ids Z)%ML{ D|qu ?Xs,d.oD/eZ~["fblFbIUpEYw跿D[@xk'Nէ˒;{ FC[txBv0Ie{U!A]+PJ# DѓGH &PXط(!:4q^s?cSءyeŌR.ƙ NuOb8BtQ`s,0fxu-ysrZABMVjmvҀ1Ħ[r)22ɢ_=k)R"qh Pޤj +lW:-9 ^,z\M Ѵ _I Ő)13rta<0⽽\qrW}ҽuX"9 ?N[XQX v/M_AcAcn%8FY~[<-dY7ceJ;+$W!f@ 4qEw 'z*'^vU2~ca3R"qhܣS>9wzH8*[eKd5qDHǯL~qDy+gL hk*BIP^ XV9d3R%fqg~eft^& Qnyƙ0`KBaPVVpu< B}Y@;׻! 5.@!hW2&_no/_1yG.ΔQ0<*"hcˀ#qH|ѳEq$O %t(۷dZtrGHGEP?~%Ў0[fL^˔I.ǗQ}kg{0RXP>zu(j. Ab?C%לF޲au*0NzDX`b*Wf7G8ΥDE2*m57dʬkw!Tbc秬G=Fۻl/r'6BE@%>]{kwgO%ZYP@#IuћuD ,F$MI 1i͢XybцN+4suɡ!u4o*x}qJ?ʥ mG)&f喙wh asu'G5$⮧'Mg0H~~"qmGH3 gkaHn h \}E*qáG:zV9;pt[PּE` i`C,\{jh{LtY)9pP9H9,L +*RGܗP"lugEmPI z .xM*\[}]KgC`t\^vY +AFn~^%By/y0{G= +[hl$@%c쑱`0]@4=Pn'_JqNAobT%lQ k8m!uv)r@4$=\=rH_eT)iٙL (4ܶ4..BGGEVV/k!.3膁b FhtbI&*F>qmm5 +t0iI^&F$" 56uEJr?iOpX*n`E xF7(:upnA7osPwzW#i ex-L@ 8 yk"D|[H>0[l#zM Qъ;3_% bvz w6ށ2 +w".g:׉Q{hő3p`{9lVvwX߻wc#*5@`G;e:NLW=2 j!["Np|u"iBV{z:Q{ܭFߊR>;k1/w;t Y4iRFtxB񛱄]PND0 Ǟ&L:BHlD*;q c`ǗeqJê#BfT_Ḋ| +N{eHVemi3 f;t\ "v9}m,ڂ1{ p'B͹@6ή>9DP&ZƞD@d*rQ')T_MJ}͗&ީ$B޴Cp!#:BP_qtV:aŬTSvĜ?ϛv\(|\c&ݻ瑅G"΅V+l4rW+deHWp3| m&H51›(:P&ng97@s0yA){GJ1GM!V߫>K.֟fS3ΡWҔzH&M笜KN1k} *iu`l\/{WJdl2nfS񸈖Acm J!,Lv"BL&ہjYal ν=ncD[?Ҁ<7ٞ}>ݏFT_dBH_yNke2F8 V"^RJywM# s\Hx;Ёgm<)50:wĮFn@m/3ƮrG[XxE +Q{xx6Cb9QA)x'h<7ų& gkzkA`J,2M㎭8K,֮D]bh·!1=p3_tGW&1<<йٰ!쭉8c. Plކe_>|uL5L<-Jඎ9Eĵvg0l*DCr@횰"/ү\ 0GHLo56z$Q +h1T] ~c8vV@;4IvnLN^:;M-wQc˟u)s1` ;3[@)(Qy̌9k.\y$Jfoo \:nqE0m_ی5$ǒs %Ǜ˼/[RMe@t/I -}["x@#%~Xץ~M~]?7ܶf16Nl4Xy + +Z~ +Zj{yZCtyld@JkUǩN<x4 M?n8.NUGSZy\9"w?$-<´XGmݢE)蚌JZ(aSXӣu9V90_>^]*>GGuI+*{r<%j#ߴ!35k@5imVGLmI$KGّǣS#7m* +z6 5I^!~fOKEF +"'$\|D߽NGE/wcwr;;ױXNz:{䭑![d8)#} +qp|K^ike9>`mBoҳ_ƖUA$^J-;2T$Cgte/.sHhLSQ&"kg뺌zUz 6 O lQTL<1] $UD JĄBr卨!ՎaZ&pD 4oD!.&Fssui];^ U݆ ܇wrE((5uVO \ߦ )`|D!u|jKPJNH%kL@KQS9;L 7rD#Л`'.>6;ٞ3.r#qcC;&)Lgh b0 2.͉ff!O$-qSHo)E[\椖eBFo]ζ; Tte7tt'pڠ?E:gg/Y:vR] 0۩~BˠOL1]KPsg~>r:{+FP$uN}$Q +e_s؄!dNȋĊQ Ng,MġYk\b ԅ-м=J 9;Z[?X)p5cΝ:gh=za:c̬*)UU\KIYbܢus4Z[ygQD/hj`rV=C3ǗI_䙳Fr,N87km +Q6D R*aB 0QޑPlB '"{? xt_M[T)T2%f0# +:ɣ{Yl"|"= UX=yf/VW AUgf(="G؈#fsb +L'I]yi]8޽&+*PT+:gzFω&>|ؐf;'Bh]Ay½@as׊ JqU> S@ Sn0I7hVAڒ @ߺ6ÿ vc/Es,@@/:1x[kdۃ +2o^J;OY~G؅־"v40qSo@$yfu;0A: $ |;4mpL> sf:DYs)tqIDu.Zl]uNS!'>zøWU,\#'3԰/&&-#N" sXCJ zX NjʹEt{Rdt9'E%J8`$i3\Ȣ6BlzYA]lm~XW:U*sj $5oP=ۧ\(ve8CRB!d] ӗ;[^* I}yfi$n"nDr62a.c +eA[-NDKS"pX5k(^4gռ2qM[5MtOS}+>Ow06)b)oځkyn J}#cs $tRNnV,iy9<}z8Y]/gѻYkz7LiZtVg[{Qk^B~uз<<zJ&;e,_nqG":z/x54| wMyܡ\iP.Ds>Dwz~ui4W)ǧ, ו>l7 :xU\ $Zi: "n /ߴ/N6 I 7.afpH+A X~nEpϕ;lb }A,s1\۬<[D4^~c +l 4C l2Ocj?Fi`2]˳U_q=dmv7̰9׉GR>Ĵ;.jFvOٛ1Wk> +ʛ[T|CE,8=g`RcD??WF`4V{sIͧIxb0PLueP9n; )3(zyYؔZD( h$zxB@[WY ?Wr-6eJ'`3`oQ7ɀ{p8w)NruK흡qsa :Y#jz'u}: +2ŇA̾65jD3r+.9q{pbI,QQ]6ge꺸^ HMI} xiXlLi#2icԊdw,*xBeE(<$\ALpfƖHxX&))Cs7&-JUW`umq710lAVrۧr{Р5U%-=oW02R^Ccad 2].RR$. +;,ia?6sGֳǡ1=}t"DYnp^~?-_g_}BuHUI317[ƐMT y49A\ٯEۧw0 09)Ok[ ?U\j+:{ 'MIo|I r}zxVcNqW Swş>x=]¢;Ce9A-.$UCRp*praçccM '[Tw҃ {u0K-VLj +'a'.Bw8XcrWDdd1dO-:N-4V)Ҕ݂7 5/y D/.if-~ %t&D}gSd'8|6Q.|B A@:xS1``1"O~n4P ,-:.goic4i4| aݼ$x`rGF HaMdG%IVpOBL[ѵέ"Ѷl +5 W*LLk[ZX`A5gWɨ[U JKz4آ>‹ugYGE(z~.넒# 9` G9ԉ)7WzwXTEa:@>HK̪?cT\jtv`t'\Ol*8n?65JB # ɫNɇ~#|zY,"S{In?[DGŬQΝ +-<_A^iALмBm7~N I:ׁEf`yI.]BxyUL0?,iq57*B\4bK˒;mġ><5߃V8S `x+DLri@8D)!uROOeH@7o !0L KDve Knk/j^f!+t׻$,*ǫG4%'bjt!o|iJ3QFJ`"Bz_|?ߜL! Gt>siܗ +$e]IO*zxv C/N + /[ڮE; ZBP@骪v.O7.K= !rzQ" 2:SSơ,I'XǞoQ__WT< \EB@<4_(AG-Kq VS詡 + +D\q|WJ5`/=Vw.C*@R`'`CdPsa~pUBLj_ ֋z)9K%oftcdž)]T'jљqGGѯ@%z>8FrHh@a@* Da1|1:“Y8aW@Þv[ڀMn *X~3GV ڦR(X4|"՟oC&g:gN :8T^ ; + w +Qgv{aO}G\ +0i}hr׌uc\HI˽$Zܸ{BtIWF c BTG'wߵ礟u-:Ћ̒%Ѩ>;gPnwΑ\!}AS3H0[}/rɷOluj1("pB6 P]?G&Qi",8YM>uK )r40@E"p1N(;Nǐ(aPɲW<S+7 *9O.>Q 8~!g\$w[j@/ZT%,O|GY5G"G(lXXgYJsR0F8'5k{ U' ovZfO;z^& ΄ϣ.lXjV -V +c6Y<ӣ+ % I~dV':^؄d4MJ͟WXBxߒ0Rb,*^uaLu<ٹYs |IkK(H%==N'3Q[; @'\N&IVͦ/ ry=ZG#]ilusrIRVTL5?>B> rKZVhT`2bS?TcEܰ[~\yIB6`#dž`fU `r,^ r2tܹ9Nt_ /a~I4f;ŵl<>SM-UʞE¡*G/r` ӽ Ly{edӃZ`[2!yui_v<.; p ⵎ|~Xs 7̩{Zh֤23pP8qX%-w᎑;*KTJ:ԩLQ_t&,FyAA,Нw?U_ %f1P^}{ aoع`YQK)o'\NR}3 +~ҏuΜ#n` DXb=xnDۧw18vaڞ ȫ繣[QP? z{$瓢ׁz-S.dy6y6XL@i̘>A!)x Y)eE!I=A)|&IoԖ۟:#ZD +"mS]z;_ Q\/G4(mH0&*9o<&vB[C"on]$šҕ߃_i꫐)㣵a3P* +1+}4 0_󒅔IS@<I2TcNJ*-غ; +UaƔ0LmWRdn*%KCjXwFF'Q$ G<:Xo#_yKVqt`Gvk c=Ă)op` vOP9$C[`i@ j-EOj2r,TmImN'I=D;W +z|H⒅&)/?u5 +l4|X8M-!RAFѦ&sjD%˸ƅhiܳ/Ҏ!JۯL ) #ɋ"B[> 4̉,{J$C`jXy}rRC"̧c˥kp%o奈6ᬪRTkGN~TA- [ݵڤ&WG׻F1E :{SECx5 M)6q]" +#d%$ 5 liy꾓ŨvSɭ3zwi{C˚2W_"6s&p<B:Q 6DM"۶q˔up\ny0U>"#W\`\3Xu`jAz:ac~ΕpH` ~bVҷ+VT4P 0fNkbAǂ!!?EzReJ F J)H,ȡQ,>x*$4'(+rNJ!2I&O^LVBcWmDOzbxA ݨ|vCʶ*☍ 5>H+&Qn ^ \:>ӊ >^>Dݸ0'Օd)^& KE3*0՜}5$ZזMn7 ^$ *eߋʃ1@h+s/O BbO8hkdIU{!EXN o;ܔ^ppCĎ:ZQl?݀]CՔ+|+֪2M8Zd3tMyh%ǢzNc N+[V[%}0P2}i/E_O{)8B֛:~Yi} -?a,a@$M7TJf=6*QScNEqnXOƌ}@XL|\p bKtj&~[+Ӝ#O\(vMD8 d8?C ح%\1'NӅ +[ 93 ?gmJMMo2+|.q@hYX:[G@p PR+l@JC1~gYUNB7a"5(#"ҭ\4n[dM5J%{֐C#XΨ(O_X/8[unlYsJ`a3thz6Hgm/R0ۂ,ǁ )! m(lLW)TO{ؑrP4U7pNkp $7V3DCH=d߂rJ{Q Z9O!-'.P< Tv3.wl#;A 1zo ?iD!^Ne%;.wkXǰ +D ~*cm ta6ia +,cqrN^F۲DN<%O ?QKUMXF:( :^z ECc B$q!y6ZƇlDC4A}x䢘g'[uAw]6@3שft:C.⏌. :*hҊ> ѫ% l0=}@8[I=T]D + /}E>ٚgWս8@3G(]B*a,N :&qaЦ9\fG&G>T'VSS k{aG0b3<2z/3h_CG̼O!A_`>Wf"nXsUȻ=L.,ݰ:(~1 /@=0"ؗہ_ g +-\β C$@l#!$ TS"6ieY8Dlr-n6# -ԭ~/P[͍@97? Y~Z@ض%Q})2ЕF +DnG_$au.e@h/]^E ZOyeCĝ#!%PI"ڊpJc_yiYo-"*T}4b#J@ 6!51 x!4{植Ġ>_\PU9rKܱw %<1om^PZK\Y0Q!2!c19 FB@lBd_IsdWQywAURV* F4X)E֡"$1#@ZQWEm{upƤ5"_jq{z }Jų3!b j<*LQBnPw +AK<y^˅`q]:`9B +5. 43N>Ўi56SG55'FVX|N0&-&]9foJH0h.frC(w1%sk{1ѶSb0uWBW#M_L]G{ t8~u#G/^h/F+_e;Q6}, oT% 4J;th"pz8@qnhaG.JIDS BZOn>o %v6l!c?-1I17^<(XR/jX'ǩˌULtnM &բdBzM9<0n#@9gShX#jSÖy?b)u˓ \=utu69WF=DvW@4M cqo'CSEByYgJB6"})#C'`ngm8 LH%'1ZtU9:]9퓌$NQw0–}$x&kNdJ%ӂ +q" B݌x̟ik5d,>iy,R2j)1Ahn֠42*mfr]ɤ喸 (pY(҂BnJq*yYi0fDž92QcjzguE _;05{3^,4x \q0\XA6zu‡ഥֆ1?qRSR+⣾I3x;J`D[dZU;tGn [En"݉gq_1sHqg~mc.K wzo>XHrNaڄFp˾۱gֺ!(fQϴ1_F`] m$Lg-v,I×z̞c:f-4ǝNV켌ïs`v[4cqT`菓׼k|^FǾX2{Z нLعx 4콜B4SJ_Dd-/p),fqS:_=#<8l"%L{ Ȕȹ3ś" >;!C>9Olpa +:RrW1poбաJg\Dniːy5jm"7z8Ѽ5vlhA!Ru&0~|NZC>GM8`P'L;w +Fg7,v,RT ;XؑfS͖{te2-'F ur w:Ix`QVO^د{ґX{}cs|%=cTw@S{TP KÜ.:W1| Ns`9( +7$vE<3Vw ]qƤ{d(r&UħF5Gg,{]ltf]N=x%B .Xyݯ5IФ:/? eRB/,{s#P=,Sx`oɆ)=[!٨vqu'N)/íjN+X.MYrkx=f]SFR@@akg.9(~SUHhKDâ*akYAî $qNZI%pvB@D+'dII6A@~EF&s|T #a{V`K^Z<0pR.ڗr95WGfG?pQy'ҋΝ|< ZH_.tJOC>|oo??gt}>?~i4/mRDq'hb Z背9YQDI %WG*&)>dYvZ8:_ +;ݧ;EQP}DL/sm׃Ͻ>@1,תݵJ[O\lm"`bPW]]T@U1+1gVSR@bqCklD-JlNj;P +EJc\+J*x +Ðc$y +Ll.@vޱV x 1V >@HĴ'y',LGS1S0zŷC+@q7v.:ńexqZ{h˔uH \N|Ʒӊ/hx`_j-*%+̜4' 5Wiuv}l /jc4|=nCo_q2OzL{dƑU=<4SwJA_ev|I /A_Je}Nz*,VȯsW]ꅔӃAc v$i2DY> TBJ'9ðOӈ4 כ(_ĨN9 (gc)'UqFqÍʴ 8O)Ҳ{(ՃW;*Ȏ~5_}L[! kU! ?8QLRo=#{}WbWČFլy .wˈybɣsg%x}v= Q aJ> H[ =*54\( +RDr~=դʆ}\^_,( +5[ې-EԘ^Y&@dQl=U䉰:4wLjpn6ø|=7Oo ?xoo?ϿW_ߝ m%_ÿi\rӯ~??OϏ~??7?˟??_?i endstream endobj 6 0 obj [5 0 R] endobj 20 0 obj <> endobj xref 0 21 0000000000 65535 f +0000000016 00000 n +0000000144 00000 n +0000025786 00000 n +0000000000 00000 f +0000043971 00000 n +0000108138 00000 n +0000025837 00000 n +0000026168 00000 n +0000044270 00000 n +0000044157 00000 n +0000042969 00000 n +0000043410 00000 n +0000043458 00000 n +0000044041 00000 n +0000044072 00000 n +0000044343 00000 n +0000044517 00000 n +0000045802 00000 n +0000055602 00000 n +0000108161 00000 n +trailer <<789BB656F89545E690763E9D89E26D02>]>> startxref 108359 %%EOF \ No newline at end of file diff --git a/docs/_site/artwork/draco3d-vert.svg b/docs/_site/artwork/draco3d-vert.svg new file mode 100644 index 0000000..3a443af --- /dev/null +++ b/docs/_site/artwork/draco3d-vert.svg @@ -0,0 +1,374 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_site/assets/css/pygments/README.md b/docs/_site/assets/css/pygments/README.md new file mode 100644 index 0000000..83c205a --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/UNLICENSE.txt b/docs/_site/assets/css/pygments/UNLICENSE.txt new file mode 100644 index 0000000..cf1ab25 --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/autumn.css b/docs/_site/assets/css/pygments/autumn.css new file mode 100644 index 0000000..a5f3d4c --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/borland.css b/docs/_site/assets/css/pygments/borland.css new file mode 100644 index 0000000..2e98c79 --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/bw.css b/docs/_site/assets/css/pygments/bw.css new file mode 100644 index 0000000..632756b --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/colorful.css b/docs/_site/assets/css/pygments/colorful.css new file mode 100644 index 0000000..e5abd69 --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/default.css b/docs/_site/assets/css/pygments/default.css new file mode 100644 index 0000000..8070f2f --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/emacs.css b/docs/_site/assets/css/pygments/emacs.css new file mode 100644 index 0000000..489c0ad --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/friendly.css b/docs/_site/assets/css/pygments/friendly.css new file mode 100644 index 0000000..846e048 --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/fruity.css b/docs/_site/assets/css/pygments/fruity.css new file mode 100644 index 0000000..9152350 --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/github.css b/docs/_site/assets/css/pygments/github.css new file mode 100644 index 0000000..5c45e67 --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/index.html b/docs/_site/assets/css/pygments/index.html new file mode 100644 index 0000000..4d692ed --- /dev/null +++ b/docs/_site/assets/css/pygments/index.html @@ -0,0 +1,27 @@ +

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.

+ + + + + +

Hacking

+ +

If you want to hack on the site, check out the gh-pages branch.

+ +

Acknowledgements

+

Forked from richleland/pygments-css.

diff --git a/docs/_site/assets/css/pygments/manni.css b/docs/_site/assets/css/pygments/manni.css new file mode 100644 index 0000000..d5bc47e --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/monokai.css b/docs/_site/assets/css/pygments/monokai.css new file mode 100644 index 0000000..5ce9493 --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/murphy.css b/docs/_site/assets/css/pygments/murphy.css new file mode 100644 index 0000000..482d46b --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/native.css b/docs/_site/assets/css/pygments/native.css new file mode 100644 index 0000000..eac4a78 --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/pastie.css b/docs/_site/assets/css/pygments/pastie.css new file mode 100644 index 0000000..538bdc6 --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/perldoc.css b/docs/_site/assets/css/pygments/perldoc.css new file mode 100644 index 0000000..50516f2 --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/tango.css b/docs/_site/assets/css/pygments/tango.css new file mode 100644 index 0000000..bfd3803 --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/trac.css b/docs/_site/assets/css/pygments/trac.css new file mode 100644 index 0000000..851ba3c --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/vim.css b/docs/_site/assets/css/pygments/vim.css new file mode 100644 index 0000000..3af4a14 --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/vs.css b/docs/_site/assets/css/pygments/vs.css new file mode 100644 index 0000000..e1e55d8 --- /dev/null +++ b/docs/_site/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/_site/assets/css/pygments/zenburn.css b/docs/_site/assets/css/pygments/zenburn.css new file mode 100644 index 0000000..287591d --- /dev/null +++ b/docs/_site/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/_site/assets/css/spec-style.css b/docs/_site/assets/css/spec-style.css new file mode 100644 index 0000000..513a264 --- /dev/null +++ b/docs/_site/assets/css/spec-style.css @@ -0,0 +1 @@ +@import url("https://fonts.googleapis.com/css?family=Inconsolata");body{font-family:Arial,sans-serif;margin:10% 25% 10% 10%;line-height:1.3}a{color:navy;text-decoration:none}a:visited{color:navy;text-decoration:none}a:hover{text-decoration:underline}pre{font-family:"Inconsolata",monospace;border:2px solid #ddd;padding:1em;margin-left:1em;overflow-x:auto}code{font-family:"Inconsolata",monospace}table{border-collapse:collapse;min-width:50%;margin-left:1em}th,td{border:2px solid #ccc;padding:.5em}th{background-color:#333;color:#fff}table.terms th{display:none}table.terms td{vertical-align:top}table.conventions th{display:none}table.conventions td{vertical-align:top}table.conventions td:first-child{white-space:nowrap}table.nohead th{display:none}table.xyhead th,table.xyhead td:first-child{background-color:#9bbb59}table.xyhead th{color:#000;font-weight:normal}figure.highlight{background-color:#f2f2f2;padding-left:1em;padding-right:1em;border:2px solid #ccc}div.syntax{background-color:#fff;background-image:linear-gradient(90deg, transparent 540px, #abced4 540px, #abced4 542px, transparent 542px),linear-gradient(#ddd .1em, transparent .1em);background-size:100% 1.3em;border-left:2px solid #ddd;border-right:2px solid #ddd;border-bottom:2px solid #ddd;white-space:pre;font-family:"Inconsolata",monospace;font-size:1em;padding-left:1em;margin-left:1em;width:720px} diff --git a/docs/_site/assets/favicon.ico b/docs/_site/assets/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4ca5dba1fb70dad00b67cf10e092bea8fcb9caf5 GIT binary patch literal 1406 zcmeHH>r;$z6nkUTum9-(T zKnFIz6|$r|-KhV$iW zh;1_=$ZUY?>&n|5_EK+Aes!F(Rz47jp7!Q3ssPl|d-XrTGRpB+y;+ z4e*ayp8J@dmq>x8k%ll$uN5a zW}8>7J>=s%FYy!`zMn?S+~CMhm_JK)YR&AR?Zo$~9F#}MGq!V9aBgqhapwsETr^@k z!)&HRD0cm(Oz={>Shpz2AI_{h>gu;>(_elvI{dW9+`pWewk&enZ`%J8DE0%?Gim$g Z1TzBtC)FG%Y~e6KNT<3na4`q2_ZQ8$6zl*1 literal 0 HcmV?d00001 diff --git a/docs/_site/assets/js/ASCIIMathML.js b/docs/_site/assets/js/ASCIIMathML.js new file mode 100644 index 0000000..727111c --- /dev/null +++ b/docs/_site/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; igCniQG(FtL6Gs5B_neCZ(TfY`b|RTNM52 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 literal 0 HcmV?d00001 diff --git a/docs/_site/assets/js/jquery.autotoc.js b/docs/_site/assets/js/jquery.autotoc.js new file mode 100644 index 0000000..20a2bd4 --- /dev/null +++ b/docs/_site/assets/js/jquery.autotoc.js @@ -0,0 +1,58 @@ +// jQuery AutoTOC +// Dynamically create a table of contents for a page with semantically correct HTML headings. +// Version 1.0, December 30, 2016 +// By Craig D. Cocca + +jQuery.fn.extend({ + autoTOC: function(options) { + + var monitoredDOMElements = new Array(); + var windowHeight = $(window).height(); + + // Make sure we keep tabs on the window height as the user changes the browser window dimensions + $(window).on("resize", function() { + windowHeight = $(window).height(); + }); + + // Bind monitor to scroll event to keep an eye which heading element is in the top quarter of the page + $(window).on("scroll",function() { + topOfWindow = $(window).scrollTop(); + bottomOfWindow = $(window).scrollTop() + (windowHeight * .25); + for(element in monitoredDOMElements) { + if( monitoredDOMElements[element].offset > 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/_site/spec/00.00.00.title.html b/docs/_site/spec/00.00.00.title.html new file mode 100644 index 0000000..3b73c4f --- /dev/null +++ b/docs/_site/spec/00.00.00.title.html @@ -0,0 +1,2 @@ + +

    {{ page.title }}

    diff --git a/docs/_site/spec/00.00.00.title.md b/docs/_site/spec/00.00.00.title.md new file mode 100644 index 0000000..fffa716 --- /dev/null +++ b/docs/_site/spec/00.00.00.title.md @@ -0,0 +1,3 @@ + +# {{ page.title }} +{:.no_toc} diff --git a/docs/_site/spec/00.00.01.version.html b/docs/_site/spec/00.00.01.version.html new file mode 100644 index 0000000..ecfa653 --- /dev/null +++ b/docs/_site/spec/00.00.01.version.html @@ -0,0 +1,3 @@ + +

    __
    +__

    diff --git a/docs/_site/spec/00.00.01.version.md b/docs/_site/spec/00.00.01.version.md new file mode 100644 index 0000000..1796d22 --- /dev/null +++ b/docs/_site/spec/00.00.01.version.md @@ -0,0 +1,3 @@ + +_{{ page.version }}_ +_{{ page.version_date }}_ diff --git a/docs/_site/spec/00.00.02.authors.html b/docs/_site/spec/00.00.02.authors.html new file mode 100644 index 0000000..289d69f --- /dev/null +++ b/docs/_site/spec/00.00.02.authors.html @@ -0,0 +1,4 @@ + +

    Frank Galligan, Google
    +[author]
    +[author]

    diff --git a/docs/_site/spec/00.00.02.authors.md b/docs/_site/spec/00.00.02.authors.md new file mode 100644 index 0000000..2cf7726 --- /dev/null +++ b/docs/_site/spec/00.00.02.authors.md @@ -0,0 +1,4 @@ + +_Frank Galligan, Google +\[author] +\[author]_ diff --git a/docs/_site/spec/00.00.03.last.modified.html b/docs/_site/spec/00.00.03.last.modified.html new file mode 100644 index 0000000..124fa6d --- /dev/null +++ b/docs/_site/spec/00.00.03.last.modified.html @@ -0,0 +1,2 @@ + +

    Last modified: 2017-07-09 18:30:06 -0700

    diff --git a/docs/_site/spec/00.00.03.last.modified.md b/docs/_site/spec/00.00.03.last.modified.md new file mode 100644 index 0000000..092b08c --- /dev/null +++ b/docs/_site/spec/00.00.03.last.modified.md @@ -0,0 +1,2 @@ + +_Last modified: {{ site.time }}_ diff --git a/docs/_site/spec/00.00.04.abstract.html b/docs/_site/spec/00.00.04.abstract.html new file mode 100644 index 0000000..595ec74 --- /dev/null +++ b/docs/_site/spec/00.00.04.abstract.html @@ -0,0 +1,5 @@ + +

    Abstract

    + +

    This document defines the bitstream format and decoding process for the +Draco 3D Data Compression scheme.

    diff --git a/docs/_site/spec/00.00.04.abstract.md b/docs/_site/spec/00.00.04.abstract.md new file mode 100644 index 0000000..2fc4a46 --- /dev/null +++ b/docs/_site/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/_site/spec/00.00.05.toc.html b/docs/_site/spec/00.00.05.toc.html new file mode 100644 index 0000000..09409a6 --- /dev/null +++ b/docs/_site/spec/00.00.05.toc.html @@ -0,0 +1,3 @@ + +

    Contents

    + diff --git a/docs/_site/spec/00.00.05.toc.md b/docs/_site/spec/00.00.05.toc.md new file mode 100644 index 0000000..9ce6baf --- /dev/null +++ b/docs/_site/spec/00.00.05.toc.md @@ -0,0 +1,5 @@ + +**Contents** + +* TOC +{:toc} diff --git a/docs/_site/spec/01.00.00.scope.html b/docs/_site/spec/01.00.00.scope.html new file mode 100644 index 0000000..d0e1a2e --- /dev/null +++ b/docs/_site/spec/01.00.00.scope.html @@ -0,0 +1,5 @@ + +

    Scope

    + +

    This document specifies the open-source Draco #D Data Compression bitstream +format and decoding process.

    diff --git a/docs/_site/spec/01.00.00.scope.md b/docs/_site/spec/01.00.00.scope.md new file mode 100644 index 0000000..d17eff9 --- /dev/null +++ b/docs/_site/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/_site/spec/02.00.00.terms.html b/docs/_site/spec/02.00.00.terms.html new file mode 100644 index 0000000..2ecb3a9 --- /dev/null +++ b/docs/_site/spec/02.00.00.terms.html @@ -0,0 +1,19 @@ + +

    Terms and Definitions

    + +

    For the purposes of this document, the following terms and definitions apply:

    + + + + + + + + + + + + + + +
    TermDefinition
      
    diff --git a/docs/_site/spec/02.00.00.terms.md b/docs/_site/spec/02.00.00.terms.md new file mode 100644 index 0000000..cfca0dd --- /dev/null +++ b/docs/_site/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/_site/spec/03.00.00.symbols.html b/docs/_site/spec/03.00.00.symbols.html new file mode 100644 index 0000000..550b9e4 --- /dev/null +++ b/docs/_site/spec/03.00.00.symbols.html @@ -0,0 +1,30 @@ + +

    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 nameValueDescription
    SYMBOL  
    + diff --git a/docs/_site/spec/03.00.00.symbols.md b/docs/_site/spec/03.00.00.symbols.md new file mode 100644 index 0000000..58b42cf --- /dev/null +++ b/docs/_site/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/_site/spec/04.00.00.conventions.html b/docs/_site/spec/04.00.00.conventions.html new file mode 100644 index 0000000..80fc2b5 --- /dev/null +++ b/docs/_site/spec/04.00.00.conventions.html @@ -0,0 +1,42 @@ +

    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.

      +
    • +
    diff --git a/docs/_site/spec/04.00.00.conventions.md b/docs/_site/spec/04.00.00.conventions.md new file mode 100644 index 0000000..767de7c --- /dev/null +++ b/docs/_site/spec/04.00.00.conventions.md @@ -0,0 +1,26 @@ +## 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. diff --git a/docs/_site/spec/draco.decoder.html b/docs/_site/spec/draco.decoder.html new file mode 100644 index 0000000..114ff0c --- /dev/null +++ b/docs/_site/spec/draco.decoder.html @@ -0,0 +1,43 @@ +

    Draco Decoder

    + +

    Decode()

    + +
    +Decode() { Type + DecodeHeader() + DecodeConnectivityData() + DecodeAttributeData()} + +
    + +

    DecodeHeader()

    + +
    +DecodeHeader() { Type + draco_string UI8[5] + major_version UI8 + minor_version UI8 + encoder_type UI8 + encoder_method UI8 + flags +} + +
    + +

    DecodeAttributeData()

    + +
    +DecodeAttributeData() { Type + 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() +
    diff --git a/docs/_site/spec/draco.decoder.md b/docs/_site/spec/draco.decoder.md new file mode 100644 index 0000000..99c8096 --- /dev/null +++ b/docs/_site/spec/draco.decoder.md @@ -0,0 +1,45 @@ +## Draco Decoder + +### Decode() + +
    +Decode() { Type + DecodeHeader() + DecodeConnectivityData() + DecodeAttributeData()} + +
    + + +### DecodeHeader() + +
    +DecodeHeader() { Type + draco_string UI8[5] + major_version UI8 + minor_version UI8 + encoder_type UI8 + encoder_method UI8 + flags +} + +
    + + +### DecodeAttributeData() + +
    +DecodeAttributeData() { Type + 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() +
    diff --git a/docs/_site/spec/edgebreaker.decoder.html b/docs/_site/spec/edgebreaker.decoder.html new file mode 100644 index 0000000..d5a7db7 --- /dev/null +++ b/docs/_site/spec/edgebreaker.decoder.html @@ -0,0 +1,1556 @@ +

    EdgeBreaker Decoder

    + +

    InitializeDecoder()

    + +
    +InitializeDecoder() { Type + edgebreaker_decoder_type UI8 +} + +
    + +

    DecodeConnectivity()

    + +
    +DecodeConnectivity() { Type + 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() +} + +
    + +

    AssignPointsToCorners()

    + +
    +AssignPointsToCorners() { Type + 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()); +} + +
    + +

    DecodeConnectivity()

    + +
    +DecodeConnectivity(num_symbols) { Type + 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; +} + +
    + +

    UpdateCornerTableForSymbolC()

    + +
    +UpdateCornerTableForSymbolC(corner) { Type + 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; +} + +
    + +

    UpdateCornerTableForSymbolLR()

    + +
    +UpdateCornerTableForSymbolLR(corner, symbol) { Type + 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))); +} + +
    + +

    HandleSymbolS()

    + +
    +HandleSymbolS(corner) { Type + 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); +} + +
    + +

    UpdateCornerTableForSymbolE()

    + +
    +UpdateCornerTableForSymbolE() { Type + corner_table_->MapCornerToVertex(corner, num_vertices++); + corner_table_->MapCornerToVertex(corner + 1, num_vertices++); + corner_table_->MapCornerToVertex(corner + 2, num_vertices++); +} + +
    + +

    UpdateCornerTableForInteriorFace()

    + +
    +UpdateCornerTableForInteriorFace() { Type + 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))); +} + +
    + +

    IsTopologySplit()

    + +
    +IsTopologySplit(encoder_symbol_id, *out_face_edge, Type + + *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; +} + +
    + +

    DecodeAttributeConnectivitiesOnFace()

    + +
    +DecodeAttributeConnectivitiesOnFace(corner) { Type + 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]); + } + } + } +} + +
    + +

    SetOppositeCorners()

    + +
    +SetOppositeCorners(corner_0, corner_1) { Type + corner_table_->SetOppositeCorner(corner_0, corner_1); + corner_table_->SetOppositeCorner(corner_1, corner_0); +} + +
    + +

    EdgeBreaker Hole and Topology Split Events

    + +

    DecodeHoleAndTopologySplitEvents()

    + +

    FIXME: Escaping angle brackets

    + +
    +DecodeHoleAndTopologySplitEvents() { Type + num_topologoy_splits UI32 + source_symbol_id = 0 + for (i = 0; i < num_topologoy_splits; ++i) { + DecodeVarint\<UI32\>(&delta) + split_data[i].source_symbol_id = delta + source_symbol_id + DecodeVarint\<UI32\>(&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\<UI32\>(&delta) + hole_data[i].symbol_id = delta + symbol_id + } + return bytes_decoded; +} + +
    + +

    CreateAttributesDecoder

    + +

    FIXME: Escaping angle brackets

    + +
    +CreateAttributesDecoder() { Type + 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\<AttProcessor, AttObserver\> AttTraverser; + sequencer = CreateVertexTraversalSequencer\<AttTraverser\>(encoding_data); + } else if (traversal_method == MESH_TRAVERSAL_PREDICTION_DEGREE) { + typedef PredictionDegreeTraverser\<AttProcessor, AttObserver\> AttTraverser; + sequencer = CreateVertexTraversalSequencer\<AttTraverser\>(encoding_data); + } + } else { + // TODO + } + att_controller(new SequentialAttributeDecodersController(std::move(sequencer))) + decoder_->SetAttributesDecoder(att_decoder_id, std::move(att_controller)); +} + +
    + +

    Edgebreaker Traversal Decoder

    + +

    EdgebreakerTraversal_Start()

    + +
    +EdgebreakerTraversal_Start() { Type + size UI64 + symbol_buffer_ size * UI8 + size UI64 + start_face_buffer_ size * UI8 + if (num_attribute_data_ > 0) { + attribute_connectivity_decoders_ = std::unique_ptr<BinaryDecoder[]>( + new BinaryDecoder[num_attribute_data_]); + for (i = 0; i < num_attribute_data_; ++i) { + attribute_connectivity_decoders_[i].StartDecoding() + // RansBitDecoder_StartDecoding + } +} + +
    + +

    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
    +}
    +
    +
    + +

    DecodeAttributeSeam()

    + +
    DecodeAttributeSeam(int attribute) {
    +  return attribute_connectivity_decoders_[attribute].DecodeNextBit();
    +}
    +
    +
    + +

    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<UI32>(&num_symbols, out_buffer)
    +    If (num_symbols > 0) {
    +      DecodeSymbols(num_symbols, out_buffer, &context_symbols_[i])
    +    }
    +    context_counters_[i] = num_symbols
    +  }
    +  return out_buffer;
    +}
    +
    +
    + +

    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_
    +}
    +
    +
    + +

    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_);
    +}
    +
    +
    + +

    TraversalValence_MergeVertices()

    + +
    TraversalValence_MergeVertices(dest, source) {
    +  vertex_valences_[dest] += vertex_valences_[source];
    +}
    +
    +
    + +

    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;
    +}
    +
    +
    + +

    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))
    +}
    +
    +
    + +

    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()
    +  }
    +}
    +
    +
    + +

    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()
    +  }
    +}
    +
    +
    + +

    Sequential Attribute Decoder

    + +
    Initialize(...) {
    +  // Init some members
    +}
    +
    +
    + +

    DecodeValues()

    + +
    DecodeValues(const std::vector<PointIndex> &point_ids) {
    +  num_values = point_ids.size();
    +  entry_size = attribute_->byte_stride();
    +  std::unique_ptr<uint8_t[]> 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;
    +  }
    +}
    +
    +
    + +

    Sequential Integer Attribute Decoder

    + +
    Initialize(...) {
    +  SequentialAttributeDecoder_Initialize()
    +}
    +
    +
    + +

    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)
    +}
    +
    +
    + +

    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()
    +}
    +
    +
    + +

    Sequential Quantization Attribute Decoder

    + +
    Initialize(...) {
    +  SequentialIntegerAttributeDecoder_Initialize()
    +}
    +
    +
    + +

    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()
    +}
    +
    +
    + +

    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;
    +  }
    +}
    +
    +
    + +

    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];
    +  }
    +}
    +
    +
    + +

    Prediction Scheme Wrap Transform

    + +

    DecodeTransformData()

    + +
    DecodeTransformData(buffer) {
    +  min_value_                                                                 DT
    +  max_value_                                                                 DT
    +}
    +
    +
    + +

    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_;
    +    }
    +}
    +
    +
    + +

    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];
    +}
    +
    +
    + +

    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()
    +    }
    +  }
    +}
    +
    +
    + +

    MeshPredictionSchemeParallelogramShared

    + +

    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;
    +}
    +
    +
    + +

    CornerTable Traversal Processor

    + +

    IsFaceVisited()

    + +
    IsFaceVisited(corner_id) {
    +  if (corner_id < 0)
    +    return true
    +  return is_face_visited_[corner_id / 3];
    +}
    +
    +
    + +

    MarkFaceVisited()

    + +
    MarkFaceVisited(face_id) {
    +  is_face_visited_[face_id] = true;
    +}
    +
    +
    + +

    IsVertexVisited()

    + +
    IsVertexVisited(vert_id) {
    +  return is_vertex_visited_[vert_id];
    +}
    +
    +
    + +

    MarkVertexVisited()

    + +
    MarkVertexVisited(vert_id) {
    +  is_vertex_visited_[vert_id] = true;
    +}
    +
    +
    + +

    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++;
    +}
    +
    +
    + +

    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
    +        }
    +      }
    +    }
    +  }
    +}
    +
    +
    + +

    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();
    +}
    +
    +
    + +

    ProcessCorner()

    + +
    ProcessCorner(corner_id) {
    +  traverser_.TraverseFromCorner(corner_id);
    +}
    +
    +
    + +

    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);
    +    }
    +  }
    +}
    +
    +
    + +

    PointsSequencer

    + +

    AddPointId()

    + +
    AddPointId(point_id) {
    +  out_point_ids_->push_back(point_id);
    +}
    +
    +
    + +

    Corner Table

    + +

    Opposite()

    + +
    Opposite(corner) {
    +  return opposite_corners_[corner];
    +}
    +
    +
    + +

    Next()

    + +
    Next(corner) {
    +  return LocalIndex(++corner) ? corner : corner - 3;
    +}
    +
    +
    + +

    Previous()

    + +
    Previous(corner) {
    +  return LocalIndex(corner) ? corner - 1 : corner + 2;
    +}
    +
    +
    + +

    Vertex()

    + +
    Vertex(corner) {
    +  faces_[Face(corner)][LocalIndex(corner)];
    +}
    +
    +
    + +

    Face()

    + +
    Face(corner) {
    +  return corner / 3;
    +}
    +
    +
    + +

    LocalIndex()

    + +
    LocalIndex(corner) {
    +  return corner % 3;
    +}
    +
    +
    + +

    num_vertices()

    + +
    num_vertices() {
    +  return vertex_corners_.size();
    +}
    +
    +
    + +

    num_corners()

    + +
    num_corners() {
    +  return faces_.size() * 3;
    +}
    +
    +
    + +

    num_faces()

    + +
    num_faces() {
    +  return faces_.size();
    +}
    +
    +
    + +

    bool IsOnBoundary()

    + +
    bool IsOnBoundary(vert) {
    +  corner = LeftMostCorner(vert);
    +  if (SwingLeft(corner) < 0)
    +    return true;
    +  return false;
    +}
    +
    +
    + +

    SwingRight()

    + +
    SwingRight(corner) {
    +  return Previous(Opposite(Previous(corner)));
    +}
    +
    +
    + +

    SwingLeft()

    + +
    SwingLeft(corner) {
    +  return Next(Opposite(Next(corner)));
    +}
    +
    +
    + +

    GetLeftCorner()

    + +
    GetLeftCorner(corner_id) {
    +  if (corner_id < 0)
    +     return kInvalidCornerIndex;
    +  return Opposite(Previous(corner_id));
    +}
    +
    +
    + +

    GetRightCorner()

    + +
    GetRightCorner(corner_id) {
    +  if (corner_id < 0)
    +     return kInvalidCornerIndex;
    +  return Opposite(Next(corner_id));
    +}
    +
    +
    + +

    SetOppositeCorner()

    + +
    SetOppositeCorner(corner_id, pp_corner_id) {
    +  opposite_corners_[corner_id] = opp_corner_id;
    +}
    +
    +
    + +

    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;
    +  }
    +}
    +
    +
    + +

    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;
    +  }
    +}
    +
    +
    + +

    LeftMostCorner()

    + +
    LeftMostCorner(v) {
    +  return vertex_corners_[v];
    +}
    +
    +
    + +

    MakeVertexIsolated()

    + +
    MakeVertexIsolated(vert) {
    +  vertex_corners_[vert] = kInvalidCornerIndex;
    +}
    +
    +
    + +

    Mesh Attribute Corner Table

    + +

    bool IsCornerOnSeam()

    + +
    bool IsCornerOnSeam(corner) {
    +  return is_vertex_on_seam_[corner_table_->Vertex(corner)];
    +}
    +
    +
    + +

    AddSeamEdge()

    + +
    AddSeamEdge(c) {
    +  MarkSeam(c)
    +  opp_corner = corner_table_->Opposite(c);
    +  if (opp_corner >= 0) {
    +    no_interior_seams_ = false;
    +    MarkSeam(opp_corner)
    +  }
    +}
    +
    +
    + +

    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;
    +}
    +
    +
    + +

    RecomputeVertices()

    + +
    RecomputeVertices() {
    +  // in code RecomputeVerticesInternal<false>(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);
    +    }
    +  }
    +}
    +
    +
    + +

    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)
    +  }
    +}
    +
    +
    + +

    DecodeTaggedSymbols()

    + +
    DecodeTaggedSymbols() {
    +  FIXME
    +}
    +
    +
    + +

    DecodeRawSymbols()

    + +
    DecodeRawSymbols() {
    +  max_bit_length                                                             UI8
    +  DecodeRawSymbolsInternal(max_bit_length, out_values)
    +  return symbols
    +}
    +
    +
    + +

    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
    +  }
    +}
    +
    +
    + +

    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()
    +}
    +
    +
    + +

    RansSymbolDecoder_StartDecoding()

    + +
    RansSymbolDecoder_StartDecoding() {
    +  bytes_encoded                                                              UI64
    +  buffer                                                                     bytes_encoded * UI8
    +  rans_read_init(buffer, bytes_encoded)
    +}
    +
    +
    + +

    RansSymbolDecoder_DecodeSymbol()

    + +
    RansSymbolDecoder_DecodeSymbol() {
    +  ans_.rans_read()
    +}
    +
    +
    + +

    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;
    +}
    +
    +
    + +

    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;
    +}
    +
    +
    + +

    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;
    +}
    +
    +
    + +

    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
    +}
    +
    +
    + +

    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;
    +}
    +
    +
    + +

    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;
    +}
    +
    +
    + +

    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)
    +}
    +
    +
    + +

    DecodeNextBit()

    + +
    DecodeNextBit() {
    +  uint8_t bit = rabs_desc_read(&ans_decoder_, prob_zero_);
    +  return bit > 0;
    +}
    +
    +
    + +

    Core Functions

    + +

    DecodeVarint

    + +
    DecodeVarint<IT>() {
    +  If (std::is_unsigned<IT>::value) {
    +    in                                                                       UI8
    +    If (in & (1 << 7)) {
    +      out = DecodeVarint<IT>()
    +      out = (out << 7) | (in & ((1 << 7) - 1))
    +    } else {
    +      typename std::make_unsigned<IT>::type UIT;
    +      out = DecodeVarint<UIT>()
    +      out = ConvertSymbolToSignedInt(out)
    +    }
    +    return out;
    +}
    +
    +
    + +

    ConvertSymbolToSignedInt()

    + +
    ConvertSymbolToSignedInt() {
    +  abs_val = val >> 1
    +  If (val & 1 == 0) {
    +    return abs_val
    +  } else {
    +    signed_val = -abs_val - 1
    +  }
    +  return signed_val
    +}
    +
    +
    + +

    Sequential Decoder

    + +

    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
    +      }
    +    }
    +  }
    +}
    +
    +
    diff --git a/docs/_site/spec/edgebreaker.decoder.md b/docs/_site/spec/edgebreaker.decoder.md new file mode 100644 index 0000000..495901e --- /dev/null +++ b/docs/_site/spec/edgebreaker.decoder.md @@ -0,0 +1,1674 @@ +## EdgeBreaker Decoder + +### InitializeDecoder() + +
    +InitializeDecoder() { Type + edgebreaker_decoder_type UI8 +} + +
    + + +### DecodeConnectivity() + +
    +DecodeConnectivity() { Type + 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() +} + +
    + + +### AssignPointsToCorners() + +
    +AssignPointsToCorners() { Type + 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()); +} + +
    + + +### DecodeConnectivity() + +
    +DecodeConnectivity(num_symbols) { Type + 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; +} + +
    + + +### UpdateCornerTableForSymbolC() + +
    +UpdateCornerTableForSymbolC(corner) { Type + 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; +} + +
    + + + +### UpdateCornerTableForSymbolLR() + +
    +UpdateCornerTableForSymbolLR(corner, symbol) { Type + 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))); +} + +
    + + +### HandleSymbolS() + +
    +HandleSymbolS(corner) { Type + 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); +} + +
    + + +### UpdateCornerTableForSymbolE() + +
    +UpdateCornerTableForSymbolE() { Type + corner_table_->MapCornerToVertex(corner, num_vertices++); + corner_table_->MapCornerToVertex(corner + 1, num_vertices++); + corner_table_->MapCornerToVertex(corner + 2, num_vertices++); +} + +
    + + +### UpdateCornerTableForInteriorFace() + +
    +UpdateCornerTableForInteriorFace() { Type + 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))); +} + +
    + + +### IsTopologySplit() + +
    +IsTopologySplit(encoder_symbol_id, *out_face_edge, Type + + *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; +} + +
    + + +### DecodeAttributeConnectivitiesOnFace() + +
    +DecodeAttributeConnectivitiesOnFace(corner) { Type + 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]); + } + } + } +} + +
    + + +### SetOppositeCorners() + +
    +SetOppositeCorners(corner_0, corner_1) { Type + corner_table_->SetOppositeCorner(corner_0, corner_1); + corner_table_->SetOppositeCorner(corner_1, corner_0); +} + +
    + + +## EdgeBreaker Hole and Topology Split Events + +### DecodeHoleAndTopologySplitEvents() + +FIXME: Escaping angle brackets + +
    +DecodeHoleAndTopologySplitEvents() { Type + 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; +} + +
    + +### CreateAttributesDecoder + +FIXME: Escaping angle brackets + +
    +CreateAttributesDecoder() { Type + 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)); +} + +
    + + +## Edgebreaker Traversal Decoder + +### EdgebreakerTraversal_Start() + +
    +EdgebreakerTraversal_Start() { Type + 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 + } +} + +
    + + +### 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 +} +~~~~~ + + +### DecodeAttributeSeam() + +~~~~~ +DecodeAttributeSeam(int attribute) { + return attribute_connectivity_decoders_[attribute].DecodeNextBit(); +} +~~~~~ + + +## 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; +} +~~~~~ + + + +### 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_ +} +~~~~~ + + + +### 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_); +} +~~~~~ + + + +### TraversalValence_MergeVertices() + +~~~~~ +TraversalValence_MergeVertices(dest, source) { + vertex_valences_[dest] += vertex_valences_[source]; +} +~~~~~ + + +## 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; +} +~~~~~ + + + +## 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)) +} +~~~~~ + + +### 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() + } +} +~~~~~ + + + +### 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() + } +} +~~~~~ + + +## Sequential Attribute Decoder + +~~~~~ +Initialize(...) { + // Init some members +} +~~~~~ + + +### 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; + } +} +~~~~~ + + +## Sequential Integer Attribute Decoder + +~~~~~ +Initialize(...) { + SequentialAttributeDecoder_Initialize() +} +~~~~~ + + +### 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) +} +~~~~~ + + +### 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() +} +~~~~~ + + + +## Sequential Quantization Attribute Decoder + +~~~~~ +Initialize(...) { + SequentialIntegerAttributeDecoder_Initialize() +} +~~~~~ + + +### 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() +} +~~~~~ + + +### 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; + } +} +~~~~~ + + + +## 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]; + } +} +~~~~~ + + + +## Prediction Scheme Wrap Transform + +### DecodeTransformData() + +~~~~~ +DecodeTransformData(buffer) { + min_value_ DT + max_value_ DT +} +~~~~~ + + +### 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_; + } +} +~~~~~ + + +### 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]; +} +~~~~~ + + + +## 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() + } + } +} +~~~~~ + + +MeshPredictionSchemeParallelogramShared + +### 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; +} +~~~~~ + + + +## CornerTable Traversal Processor + + +### IsFaceVisited() + +~~~~~ +IsFaceVisited(corner_id) { + if (corner_id < 0) + return true + return is_face_visited_[corner_id / 3]; +} +~~~~~ + + +### MarkFaceVisited() + +~~~~~ +MarkFaceVisited(face_id) { + is_face_visited_[face_id] = true; +} +~~~~~ + + +### IsVertexVisited() + +~~~~~ +IsVertexVisited(vert_id) { + return is_vertex_visited_[vert_id]; +} +~~~~~ + + +### MarkVertexVisited() + +~~~~~ +MarkVertexVisited(vert_id) { + is_vertex_visited_[vert_id] = true; +} +~~~~~ + + +## 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++; +} +~~~~~ + + +## 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 + } + } + } + } +} +~~~~~ + + +## 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(); +} +~~~~~ + + +### ProcessCorner() + +~~~~~ +ProcessCorner(corner_id) { + traverser_.TraverseFromCorner(corner_id); +} +~~~~~ + + +### 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); + } + } +} +~~~~~ + + +PointsSequencer + +### AddPointId() + +~~~~~ +AddPointId(point_id) { + out_point_ids_->push_back(point_id); +} +~~~~~ + + + +## Corner Table + +### Opposite() + +~~~~~ +Opposite(corner) { + return opposite_corners_[corner]; +} +~~~~~ + + +### Next() + +~~~~~ +Next(corner) { + return LocalIndex(++corner) ? corner : corner - 3; +} +~~~~~ + + +### Previous() + +~~~~~ +Previous(corner) { + return LocalIndex(corner) ? corner - 1 : corner + 2; +} +~~~~~ + + +### Vertex() + +~~~~~ +Vertex(corner) { + faces_[Face(corner)][LocalIndex(corner)]; +} +~~~~~ + + +### Face() + +~~~~~ +Face(corner) { + return corner / 3; +} +~~~~~ + + +### LocalIndex() + +~~~~~ +LocalIndex(corner) { + return corner % 3; +} +~~~~~ + + +### num_vertices() + +~~~~~ +num_vertices() { + return vertex_corners_.size(); +} +~~~~~ + + +### num_corners() + +~~~~~ +num_corners() { + return faces_.size() * 3; +} +~~~~~ + + +### num_faces() + +~~~~~ +num_faces() { + return faces_.size(); +} +~~~~~ + + +### bool IsOnBoundary() + +~~~~~ +bool IsOnBoundary(vert) { + corner = LeftMostCorner(vert); + if (SwingLeft(corner) < 0) + return true; + return false; +} +~~~~~ + + + +### SwingRight() + +~~~~~ +SwingRight(corner) { + return Previous(Opposite(Previous(corner))); +} +~~~~~ + + +### SwingLeft() + +~~~~~ +SwingLeft(corner) { + return Next(Opposite(Next(corner))); +} +~~~~~ + + +### GetLeftCorner() + +~~~~~ +GetLeftCorner(corner_id) { + if (corner_id < 0) + return kInvalidCornerIndex; + return Opposite(Previous(corner_id)); +} +~~~~~ + + +### GetRightCorner() + +~~~~~ +GetRightCorner(corner_id) { + if (corner_id < 0) + return kInvalidCornerIndex; + return Opposite(Next(corner_id)); +} +~~~~~ + + +### SetOppositeCorner() + +~~~~~ +SetOppositeCorner(corner_id, pp_corner_id) { + opposite_corners_[corner_id] = opp_corner_id; +} +~~~~~ + + + +### 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; + } +} +~~~~~ + + +### 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; + } +} +~~~~~ + + + +### LeftMostCorner() + +~~~~~ +LeftMostCorner(v) { + return vertex_corners_[v]; +} +~~~~~ + + +### MakeVertexIsolated() + +~~~~~ +MakeVertexIsolated(vert) { + vertex_corners_[vert] = kInvalidCornerIndex; +} +~~~~~ + + + +## Mesh Attribute Corner Table + +### bool IsCornerOnSeam() + +~~~~~ +bool IsCornerOnSeam(corner) { + return is_vertex_on_seam_[corner_table_->Vertex(corner)]; +} +~~~~~ + + +### AddSeamEdge() + +~~~~~ +AddSeamEdge(c) { + MarkSeam(c) + opp_corner = corner_table_->Opposite(c); + if (opp_corner >= 0) { + no_interior_seams_ = false; + MarkSeam(opp_corner) + } +} +~~~~~ + + +### 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; +} +~~~~~ + + +### 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); + } + } +} +~~~~~ + + + + +## 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) + } +} +~~~~~ + + +### DecodeTaggedSymbols() + +~~~~~ +DecodeTaggedSymbols() { + FIXME +} +~~~~~ + + + +### DecodeRawSymbols() + +~~~~~ +DecodeRawSymbols() { + max_bit_length UI8 + DecodeRawSymbolsInternal(max_bit_length, out_values) + return symbols +} +~~~~~ + + + +### 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 + } +} +~~~~~ + + +### 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() +} +~~~~~ + + +### RansSymbolDecoder_StartDecoding() + +~~~~~ +RansSymbolDecoder_StartDecoding() { + bytes_encoded UI64 + buffer bytes_encoded * UI8 + rans_read_init(buffer, bytes_encoded) +} +~~~~~ + + + +### RansSymbolDecoder_DecodeSymbol() + +~~~~~ +RansSymbolDecoder_DecodeSymbol() { + ans_.rans_read() +} +~~~~~ + + +## 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; +} +~~~~~ + + + +### 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; +} +~~~~~ + + + +### 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; +} +~~~~~ + + + + +### 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 +} +~~~~~ + + + +### 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; +} +~~~~~ + + +### 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; +} +~~~~~ + + + +## 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) +} +~~~~~ + + +### DecodeNextBit() + +~~~~~ +DecodeNextBit() { + uint8_t bit = rabs_desc_read(&ans_decoder_, prob_zero_); + return bit > 0; +} +~~~~~ + + +## 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; +} +~~~~~ + + + +### ConvertSymbolToSignedInt() + +~~~~~ +ConvertSymbolToSignedInt() { + abs_val = val >> 1 + If (val & 1 == 0) { + return abs_val + } else { + signed_val = -abs_val - 1 + } + return signed_val +} +~~~~~ + + + +Sequential Decoder + +### 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 + } + } + } +} +~~~~~ diff --git a/docs/_site/spec/index.html b/docs/_site/spec/index.html new file mode 100644 index 0000000..05d03ed --- /dev/null +++ b/docs/_site/spec/index.html @@ -0,0 +1,1927 @@ + + + + + Draco Bitstream Specification (Draft) + + + + + + +

    Draco Bitstream Specification (Draft)

    + +

    Version 1,2
    +Released 2017-xx-xx

    + +

    Frank Galligan, Google
    +[author]
    +[author]

    + +

    Last modified: 2017-07-09 18:30:06 -0700

    + +

    Abstract

    + +

    This document defines the bitstream format and decoding process for the +Draco 3D Data Compression scheme.

    + +

    Contents

    + + + +

    Scope

    + +

    This document specifies the open-source Draco #D Data Compression bitstream +format and decoding process.

    + +

    Terms and Definitions

    + +

    For the purposes of this document, the following terms and definitions apply:

    + + + + + + + + + + + + + + +
    TermDefinition
      
    + +

    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 nameValueDescription
    SYMBOL  
    + +

    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.

      +
    • +
    + +

    Draco Decoder

    + +

    Decode()

    + +
    +Decode() { Type + DecodeHeader() + DecodeConnectivityData() + DecodeAttributeData()} + +
    + +

    DecodeHeader()

    + +
    +DecodeHeader() { Type + draco_string UI8[5] + major_version UI8 + minor_version UI8 + encoder_type UI8 + encoder_method UI8 + flags +} + +
    + +

    DecodeAttributeData()

    + +
    +DecodeAttributeData() { Type + 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() +
    + +

    Mesh Decoder

    + +

    DecodeConnectivityData()

    + +
    +DecodeConnectivityData() Type + InitializeDecoder() + DecodeConnectivity() +} + +
    + +

    EdgeBreaker Decoder

    + +

    InitializeDecoder()

    + +
    +InitializeDecoder() { Type + edgebreaker_decoder_type UI8 +} + +
    + +

    DecodeConnectivity()

    + +
    +DecodeConnectivity() { Type + 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() +} + +
    + +

    AssignPointsToCorners()

    + +
    +AssignPointsToCorners() { Type + 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()); +} + +
    + +

    DecodeConnectivity()

    + +
    +DecodeConnectivity(num_symbols) { Type + 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; +} + +
    + +

    UpdateCornerTableForSymbolC()

    + +
    +UpdateCornerTableForSymbolC(corner) { Type + 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; +} + +
    + +

    UpdateCornerTableForSymbolLR()

    + +
    +UpdateCornerTableForSymbolLR(corner, symbol) { Type + 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))); +} + +
    + +

    HandleSymbolS()

    + +
    +HandleSymbolS(corner) { Type + 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); +} + +
    + +

    UpdateCornerTableForSymbolE()

    + +
    +UpdateCornerTableForSymbolE() { Type + corner_table_->MapCornerToVertex(corner, num_vertices++); + corner_table_->MapCornerToVertex(corner + 1, num_vertices++); + corner_table_->MapCornerToVertex(corner + 2, num_vertices++); +} + +
    + +

    UpdateCornerTableForInteriorFace()

    + +
    +UpdateCornerTableForInteriorFace() { Type + 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))); +} + +
    + +

    IsTopologySplit()

    + +
    +IsTopologySplit(encoder_symbol_id, *out_face_edge, Type + + *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; +} + +
    + +

    DecodeAttributeConnectivitiesOnFace()

    + +
    +DecodeAttributeConnectivitiesOnFace(corner) { Type + 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]); + } + } + } +} + +
    + +

    SetOppositeCorners()

    + +
    +SetOppositeCorners(corner_0, corner_1) { Type + corner_table_->SetOppositeCorner(corner_0, corner_1); + corner_table_->SetOppositeCorner(corner_1, corner_0); +} + +
    + +

    EdgeBreaker Hole and Topology Split Events

    + +

    DecodeHoleAndTopologySplitEvents()

    + +

    FIXME: Escaping angle brackets

    + +
    +DecodeHoleAndTopologySplitEvents() { Type + num_topologoy_splits UI32 + source_symbol_id = 0 + for (i = 0; i < num_topologoy_splits; ++i) { + DecodeVarint\<UI32\>(&delta) + split_data[i].source_symbol_id = delta + source_symbol_id + DecodeVarint\<UI32\>(&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\<UI32\>(&delta) + hole_data[i].symbol_id = delta + symbol_id + } + return bytes_decoded; +} + +
    + +

    CreateAttributesDecoder

    + +

    FIXME: Escaping angle brackets

    + +
    +CreateAttributesDecoder() { Type + 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\<AttProcessor, AttObserver\> AttTraverser; + sequencer = CreateVertexTraversalSequencer\<AttTraverser\>(encoding_data); + } else if (traversal_method == MESH_TRAVERSAL_PREDICTION_DEGREE) { + typedef PredictionDegreeTraverser\<AttProcessor, AttObserver\> AttTraverser; + sequencer = CreateVertexTraversalSequencer\<AttTraverser\>(encoding_data); + } + } else { + // TODO + } + att_controller(new SequentialAttributeDecodersController(std::move(sequencer))) + decoder_->SetAttributesDecoder(att_decoder_id, std::move(att_controller)); +} + +
    + +

    Edgebreaker Traversal Decoder

    + +

    EdgebreakerTraversal_Start()

    + +
    +EdgebreakerTraversal_Start() { Type + size UI64 + symbol_buffer_ size * UI8 + size UI64 + start_face_buffer_ size * UI8 + if (num_attribute_data_ > 0) { + attribute_connectivity_decoders_ = std::unique_ptr<BinaryDecoder[]>( + new BinaryDecoder[num_attribute_data_]); + for (i = 0; i < num_attribute_data_; ++i) { + attribute_connectivity_decoders_[i].StartDecoding() + // RansBitDecoder_StartDecoding + } +} + +
    + +

    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
    +}
    +
    +
    + +

    DecodeAttributeSeam()

    + +
    DecodeAttributeSeam(int attribute) {
    +  return attribute_connectivity_decoders_[attribute].DecodeNextBit();
    +}
    +
    +
    + +

    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<UI32>(&num_symbols, out_buffer)
    +    If (num_symbols > 0) {
    +      DecodeSymbols(num_symbols, out_buffer, &context_symbols_[i])
    +    }
    +    context_counters_[i] = num_symbols
    +  }
    +  return out_buffer;
    +}
    +
    +
    + +

    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_
    +}
    +
    +
    + +

    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_);
    +}
    +
    +
    + +

    TraversalValence_MergeVertices()

    + +
    TraversalValence_MergeVertices(dest, source) {
    +  vertex_valences_[dest] += vertex_valences_[source];
    +}
    +
    +
    + +

    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;
    +}
    +
    +
    + +

    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))
    +}
    +
    +
    + +

    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()
    +  }
    +}
    +
    +
    + +

    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()
    +  }
    +}
    +
    +
    + +

    Sequential Attribute Decoder

    + +
    Initialize(...) {
    +  // Init some members
    +}
    +
    +
    + +

    DecodeValues()

    + +
    DecodeValues(const std::vector<PointIndex> &point_ids) {
    +  num_values = point_ids.size();
    +  entry_size = attribute_->byte_stride();
    +  std::unique_ptr<uint8_t[]> 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;
    +  }
    +}
    +
    +
    + +

    Sequential Integer Attribute Decoder

    + +
    Initialize(...) {
    +  SequentialAttributeDecoder_Initialize()
    +}
    +
    +
    + +

    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)
    +}
    +
    +
    + +

    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()
    +}
    +
    +
    + +

    Sequential Quantization Attribute Decoder

    + +
    Initialize(...) {
    +  SequentialIntegerAttributeDecoder_Initialize()
    +}
    +
    +
    + +

    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()
    +}
    +
    +
    + +

    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;
    +  }
    +}
    +
    +
    + +

    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];
    +  }
    +}
    +
    +
    + +

    Prediction Scheme Wrap Transform

    + +

    DecodeTransformData()

    + +
    DecodeTransformData(buffer) {
    +  min_value_                                                                 DT
    +  max_value_                                                                 DT
    +}
    +
    +
    + +

    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_;
    +    }
    +}
    +
    +
    + +

    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];
    +}
    +
    +
    + +

    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()
    +    }
    +  }
    +}
    +
    +
    + +

    MeshPredictionSchemeParallelogramShared

    + +

    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;
    +}
    +
    +
    + +

    CornerTable Traversal Processor

    + +

    IsFaceVisited()

    + +
    IsFaceVisited(corner_id) {
    +  if (corner_id < 0)
    +    return true
    +  return is_face_visited_[corner_id / 3];
    +}
    +
    +
    + +

    MarkFaceVisited()

    + +
    MarkFaceVisited(face_id) {
    +  is_face_visited_[face_id] = true;
    +}
    +
    +
    + +

    IsVertexVisited()

    + +
    IsVertexVisited(vert_id) {
    +  return is_vertex_visited_[vert_id];
    +}
    +
    +
    + +

    MarkVertexVisited()

    + +
    MarkVertexVisited(vert_id) {
    +  is_vertex_visited_[vert_id] = true;
    +}
    +
    +
    + +

    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++;
    +}
    +
    +
    + +

    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
    +        }
    +      }
    +    }
    +  }
    +}
    +
    +
    + +

    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();
    +}
    +
    +
    + +

    ProcessCorner()

    + +
    ProcessCorner(corner_id) {
    +  traverser_.TraverseFromCorner(corner_id);
    +}
    +
    +
    + +

    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);
    +    }
    +  }
    +}
    +
    +
    + +

    PointsSequencer

    + +

    AddPointId()

    + +
    AddPointId(point_id) {
    +  out_point_ids_->push_back(point_id);
    +}
    +
    +
    + +

    Corner Table

    + +

    Opposite()

    + +
    Opposite(corner) {
    +  return opposite_corners_[corner];
    +}
    +
    +
    + +

    Next()

    + +
    Next(corner) {
    +  return LocalIndex(++corner) ? corner : corner - 3;
    +}
    +
    +
    + +

    Previous()

    + +
    Previous(corner) {
    +  return LocalIndex(corner) ? corner - 1 : corner + 2;
    +}
    +
    +
    + +

    Vertex()

    + +
    Vertex(corner) {
    +  faces_[Face(corner)][LocalIndex(corner)];
    +}
    +
    +
    + +

    Face()

    + +
    Face(corner) {
    +  return corner / 3;
    +}
    +
    +
    + +

    LocalIndex()

    + +
    LocalIndex(corner) {
    +  return corner % 3;
    +}
    +
    +
    + +

    num_vertices()

    + +
    num_vertices() {
    +  return vertex_corners_.size();
    +}
    +
    +
    + +

    num_corners()

    + +
    num_corners() {
    +  return faces_.size() * 3;
    +}
    +
    +
    + +

    num_faces()

    + +
    num_faces() {
    +  return faces_.size();
    +}
    +
    +
    + +

    bool IsOnBoundary()

    + +
    bool IsOnBoundary(vert) {
    +  corner = LeftMostCorner(vert);
    +  if (SwingLeft(corner) < 0)
    +    return true;
    +  return false;
    +}
    +
    +
    + +

    SwingRight()

    + +
    SwingRight(corner) {
    +  return Previous(Opposite(Previous(corner)));
    +}
    +
    +
    + +

    SwingLeft()

    + +
    SwingLeft(corner) {
    +  return Next(Opposite(Next(corner)));
    +}
    +
    +
    + +

    GetLeftCorner()

    + +
    GetLeftCorner(corner_id) {
    +  if (corner_id < 0)
    +     return kInvalidCornerIndex;
    +  return Opposite(Previous(corner_id));
    +}
    +
    +
    + +

    GetRightCorner()

    + +
    GetRightCorner(corner_id) {
    +  if (corner_id < 0)
    +     return kInvalidCornerIndex;
    +  return Opposite(Next(corner_id));
    +}
    +
    +
    + +

    SetOppositeCorner()

    + +
    SetOppositeCorner(corner_id, pp_corner_id) {
    +  opposite_corners_[corner_id] = opp_corner_id;
    +}
    +
    +
    + +

    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;
    +  }
    +}
    +
    +
    + +

    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;
    +  }
    +}
    +
    +
    + +

    LeftMostCorner()

    + +
    LeftMostCorner(v) {
    +  return vertex_corners_[v];
    +}
    +
    +
    + +

    MakeVertexIsolated()

    + +
    MakeVertexIsolated(vert) {
    +  vertex_corners_[vert] = kInvalidCornerIndex;
    +}
    +
    +
    + +

    Mesh Attribute Corner Table

    + +

    bool IsCornerOnSeam()

    + +
    bool IsCornerOnSeam(corner) {
    +  return is_vertex_on_seam_[corner_table_->Vertex(corner)];
    +}
    +
    +
    + +

    AddSeamEdge()

    + +
    AddSeamEdge(c) {
    +  MarkSeam(c)
    +  opp_corner = corner_table_->Opposite(c);
    +  if (opp_corner >= 0) {
    +    no_interior_seams_ = false;
    +    MarkSeam(opp_corner)
    +  }
    +}
    +
    +
    + +

    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;
    +}
    +
    +
    + +

    RecomputeVertices()

    + +
    RecomputeVertices() {
    +  // in code RecomputeVerticesInternal<false>(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);
    +    }
    +  }
    +}
    +
    +
    + +

    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)
    +  }
    +}
    +
    +
    + +

    DecodeTaggedSymbols()

    + +
    DecodeTaggedSymbols() {
    +  FIXME
    +}
    +
    +
    + +

    DecodeRawSymbols()

    + +
    DecodeRawSymbols() {
    +  max_bit_length                                                             UI8
    +  DecodeRawSymbolsInternal(max_bit_length, out_values)
    +  return symbols
    +}
    +
    +
    + +

    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
    +  }
    +}
    +
    +
    + +

    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()
    +}
    +
    +
    + +

    RansSymbolDecoder_StartDecoding()

    + +
    RansSymbolDecoder_StartDecoding() {
    +  bytes_encoded                                                              UI64
    +  buffer                                                                     bytes_encoded * UI8
    +  rans_read_init(buffer, bytes_encoded)
    +}
    +
    +
    + +

    RansSymbolDecoder_DecodeSymbol()

    + +
    RansSymbolDecoder_DecodeSymbol() {
    +  ans_.rans_read()
    +}
    +
    +
    + +

    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;
    +}
    +
    +
    + +

    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;
    +}
    +
    +
    + +

    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;
    +}
    +
    +
    + +

    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
    +}
    +
    +
    + +

    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;
    +}
    +
    +
    + +

    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;
    +}
    +
    +
    + +

    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)
    +}
    +
    +
    + +

    DecodeNextBit()

    + +
    DecodeNextBit() {
    +  uint8_t bit = rabs_desc_read(&ans_decoder_, prob_zero_);
    +  return bit > 0;
    +}
    +
    +
    + +

    Core Functions

    + +

    DecodeVarint

    + +
    DecodeVarint<IT>() {
    +  If (std::is_unsigned<IT>::value) {
    +    in                                                                       UI8
    +    If (in & (1 << 7)) {
    +      out = DecodeVarint<IT>()
    +      out = (out << 7) | (in & ((1 << 7) - 1))
    +    } else {
    +      typename std::make_unsigned<IT>::type UIT;
    +      out = DecodeVarint<UIT>()
    +      out = ConvertSymbolToSignedInt(out)
    +    }
    +    return out;
    +}
    +
    +
    + +

    ConvertSymbolToSignedInt()

    + +
    ConvertSymbolToSignedInt() {
    +  abs_val = val >> 1
    +  If (val & 1 == 0) {
    +    return abs_val
    +  } else {
    +    signed_val = -abs_val - 1
    +  }
    +  return signed_val
    +}
    +
    +
    + +

    Sequential Decoder

    + +

    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
    +      }
    +    }
    +  }
    +}
    +
    +
    + + + + + + diff --git a/docs/_site/spec/mesh.decoder.html b/docs/_site/spec/mesh.decoder.html new file mode 100644 index 0000000..d4d0d2a --- /dev/null +++ b/docs/_site/spec/mesh.decoder.html @@ -0,0 +1,11 @@ +

    Mesh Decoder

    + +

    DecodeConnectivityData()

    + +
    +DecodeConnectivityData() Type + InitializeDecoder() + DecodeConnectivity() +} + +
    diff --git a/docs/_site/spec/mesh.decoder.md b/docs/_site/spec/mesh.decoder.md new file mode 100644 index 0000000..c283bea --- /dev/null +++ b/docs/_site/spec/mesh.decoder.md @@ -0,0 +1,11 @@ +## Mesh Decoder + +### DecodeConnectivityData() + +
    +DecodeConnectivityData() Type + InitializeDecoder() + DecodeConnectivity() +} + +
    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..b7b71c6 --- /dev/null +++ b/docs/assets/css/spec-style.sass @@ -0,0 +1,99 @@ +--- +--- +/* + * 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.syntax + //background-color: $gridcolor + //background-image: linear-gradient(transparent 50%, rgba(255,255,255,.5) 50%) + //background-size: 40px 40px + background-color: #fff + background-image: linear-gradient(90deg, transparent 540px, #abced4 540px, #abced4 542px, transparent 542px), 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 0000000000000000000000000000000000000000..4ca5dba1fb70dad00b67cf10e092bea8fcb9caf5 GIT binary patch literal 1406 zcmeHH>r;$z6nkUTum9-(T zKnFIz6|$r|-KhV$iW zh;1_=$ZUY?>&n|5_EK+Aes!F(Rz47jp7!Q3ssPl|d-XrTGRpB+y;+ z4e*ayp8J@dmq>x8k%ll$uN5a zW}8>7J>=s%FYy!`zMn?S+~CMhm_JK)YR&AR?Zo$~9F#}MGq!V9aBgqhapwsETr^@k z!)&HRD0cm(Oz={>Shpz2AI_{h>gu;>(_elvI{dW9+`pWewk&enZ`%J8DE0%?Gim$g Z1TzBtC)FG%Y~e6KNT<3na4`q2_ZQ8$6zl*1 literal 0 HcmV?d00001 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; igCniQG(FtL6Gs5B_neCZ(TfY`b|RTNM52 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 literal 0 HcmV?d00001 diff --git a/docs/assets/js/jquery.autotoc.js b/docs/assets/js/jquery.autotoc.js new file mode 100644 index 0000000..20a2bd4 --- /dev/null +++ b/docs/assets/js/jquery.autotoc.js @@ -0,0 +1,58 @@ +// jQuery AutoTOC +// Dynamically create a table of contents for a page with semantically correct HTML headings. +// Version 1.0, December 30, 2016 +// By Craig D. Cocca + +jQuery.fn.extend({ + autoTOC: function(options) { + + var monitoredDOMElements = new Array(); + var windowHeight = $(window).height(); + + // Make sure we keep tabs on the window height as the user changes the browser window dimensions + $(window).on("resize", function() { + windowHeight = $(window).height(); + }); + + // Bind monitor to scroll event to keep an eye which heading element is in the top quarter of the page + $(window).on("scroll",function() { + topOfWindow = $(window).scrollTop(); + bottomOfWindow = $(window).scrollTop() + (windowHeight * .25); + for(element in monitoredDOMElements) { + if( monitoredDOMElements[element].offset > 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/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..767de7c --- /dev/null +++ b/docs/spec/04.00.00.conventions.md @@ -0,0 +1,26 @@ +## 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. diff --git a/docs/spec/draco.decoder.md b/docs/spec/draco.decoder.md new file mode 100644 index 0000000..99c8096 --- /dev/null +++ b/docs/spec/draco.decoder.md @@ -0,0 +1,45 @@ +## Draco Decoder + +### Decode() + +
      +Decode() { Type + DecodeHeader() + DecodeConnectivityData() + DecodeAttributeData()} + +
      + + +### DecodeHeader() + +
      +DecodeHeader() { Type + draco_string UI8[5] + major_version UI8 + minor_version UI8 + encoder_type UI8 + encoder_method UI8 + flags +} + +
      + + +### DecodeAttributeData() + +
      +DecodeAttributeData() { Type + 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() +
      diff --git a/docs/spec/edgebreaker.decoder.md b/docs/spec/edgebreaker.decoder.md new file mode 100644 index 0000000..495901e --- /dev/null +++ b/docs/spec/edgebreaker.decoder.md @@ -0,0 +1,1674 @@ +## EdgeBreaker Decoder + +### InitializeDecoder() + +
      +InitializeDecoder() { Type + edgebreaker_decoder_type UI8 +} + +
      + + +### DecodeConnectivity() + +
      +DecodeConnectivity() { Type + 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() +} + +
      + + +### AssignPointsToCorners() + +
      +AssignPointsToCorners() { Type + 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()); +} + +
      + + +### DecodeConnectivity() + +
      +DecodeConnectivity(num_symbols) { Type + 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; +} + +
      + + +### UpdateCornerTableForSymbolC() + +
      +UpdateCornerTableForSymbolC(corner) { Type + 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; +} + +
      + + + +### UpdateCornerTableForSymbolLR() + +
      +UpdateCornerTableForSymbolLR(corner, symbol) { Type + 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))); +} + +
      + + +### HandleSymbolS() + +
      +HandleSymbolS(corner) { Type + 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); +} + +
      + + +### UpdateCornerTableForSymbolE() + +
      +UpdateCornerTableForSymbolE() { Type + corner_table_->MapCornerToVertex(corner, num_vertices++); + corner_table_->MapCornerToVertex(corner + 1, num_vertices++); + corner_table_->MapCornerToVertex(corner + 2, num_vertices++); +} + +
      + + +### UpdateCornerTableForInteriorFace() + +
      +UpdateCornerTableForInteriorFace() { Type + 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))); +} + +
      + + +### IsTopologySplit() + +
      +IsTopologySplit(encoder_symbol_id, *out_face_edge, Type + + *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; +} + +
      + + +### DecodeAttributeConnectivitiesOnFace() + +
      +DecodeAttributeConnectivitiesOnFace(corner) { Type + 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]); + } + } + } +} + +
      + + +### SetOppositeCorners() + +
      +SetOppositeCorners(corner_0, corner_1) { Type + corner_table_->SetOppositeCorner(corner_0, corner_1); + corner_table_->SetOppositeCorner(corner_1, corner_0); +} + +
      + + +## EdgeBreaker Hole and Topology Split Events + +### DecodeHoleAndTopologySplitEvents() + +FIXME: Escaping angle brackets + +
      +DecodeHoleAndTopologySplitEvents() { Type + 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; +} + +
      + +### CreateAttributesDecoder + +FIXME: Escaping angle brackets + +
      +CreateAttributesDecoder() { Type + 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)); +} + +
      + + +## Edgebreaker Traversal Decoder + +### EdgebreakerTraversal_Start() + +
      +EdgebreakerTraversal_Start() { Type + 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 + } +} + +
      + + +### 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 +} +~~~~~ + + +### DecodeAttributeSeam() + +~~~~~ +DecodeAttributeSeam(int attribute) { + return attribute_connectivity_decoders_[attribute].DecodeNextBit(); +} +~~~~~ + + +## 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; +} +~~~~~ + + + +### 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_ +} +~~~~~ + + + +### 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_); +} +~~~~~ + + + +### TraversalValence_MergeVertices() + +~~~~~ +TraversalValence_MergeVertices(dest, source) { + vertex_valences_[dest] += vertex_valences_[source]; +} +~~~~~ + + +## 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; +} +~~~~~ + + + +## 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)) +} +~~~~~ + + +### 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() + } +} +~~~~~ + + + +### 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() + } +} +~~~~~ + + +## Sequential Attribute Decoder + +~~~~~ +Initialize(...) { + // Init some members +} +~~~~~ + + +### 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; + } +} +~~~~~ + + +## Sequential Integer Attribute Decoder + +~~~~~ +Initialize(...) { + SequentialAttributeDecoder_Initialize() +} +~~~~~ + + +### 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) +} +~~~~~ + + +### 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() +} +~~~~~ + + + +## Sequential Quantization Attribute Decoder + +~~~~~ +Initialize(...) { + SequentialIntegerAttributeDecoder_Initialize() +} +~~~~~ + + +### 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() +} +~~~~~ + + +### 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; + } +} +~~~~~ + + + +## 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]; + } +} +~~~~~ + + + +## Prediction Scheme Wrap Transform + +### DecodeTransformData() + +~~~~~ +DecodeTransformData(buffer) { + min_value_ DT + max_value_ DT +} +~~~~~ + + +### 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_; + } +} +~~~~~ + + +### 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]; +} +~~~~~ + + + +## 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() + } + } +} +~~~~~ + + +MeshPredictionSchemeParallelogramShared + +### 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; +} +~~~~~ + + + +## CornerTable Traversal Processor + + +### IsFaceVisited() + +~~~~~ +IsFaceVisited(corner_id) { + if (corner_id < 0) + return true + return is_face_visited_[corner_id / 3]; +} +~~~~~ + + +### MarkFaceVisited() + +~~~~~ +MarkFaceVisited(face_id) { + is_face_visited_[face_id] = true; +} +~~~~~ + + +### IsVertexVisited() + +~~~~~ +IsVertexVisited(vert_id) { + return is_vertex_visited_[vert_id]; +} +~~~~~ + + +### MarkVertexVisited() + +~~~~~ +MarkVertexVisited(vert_id) { + is_vertex_visited_[vert_id] = true; +} +~~~~~ + + +## 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++; +} +~~~~~ + + +## 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 + } + } + } + } +} +~~~~~ + + +## 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(); +} +~~~~~ + + +### ProcessCorner() + +~~~~~ +ProcessCorner(corner_id) { + traverser_.TraverseFromCorner(corner_id); +} +~~~~~ + + +### 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); + } + } +} +~~~~~ + + +PointsSequencer + +### AddPointId() + +~~~~~ +AddPointId(point_id) { + out_point_ids_->push_back(point_id); +} +~~~~~ + + + +## Corner Table + +### Opposite() + +~~~~~ +Opposite(corner) { + return opposite_corners_[corner]; +} +~~~~~ + + +### Next() + +~~~~~ +Next(corner) { + return LocalIndex(++corner) ? corner : corner - 3; +} +~~~~~ + + +### Previous() + +~~~~~ +Previous(corner) { + return LocalIndex(corner) ? corner - 1 : corner + 2; +} +~~~~~ + + +### Vertex() + +~~~~~ +Vertex(corner) { + faces_[Face(corner)][LocalIndex(corner)]; +} +~~~~~ + + +### Face() + +~~~~~ +Face(corner) { + return corner / 3; +} +~~~~~ + + +### LocalIndex() + +~~~~~ +LocalIndex(corner) { + return corner % 3; +} +~~~~~ + + +### num_vertices() + +~~~~~ +num_vertices() { + return vertex_corners_.size(); +} +~~~~~ + + +### num_corners() + +~~~~~ +num_corners() { + return faces_.size() * 3; +} +~~~~~ + + +### num_faces() + +~~~~~ +num_faces() { + return faces_.size(); +} +~~~~~ + + +### bool IsOnBoundary() + +~~~~~ +bool IsOnBoundary(vert) { + corner = LeftMostCorner(vert); + if (SwingLeft(corner) < 0) + return true; + return false; +} +~~~~~ + + + +### SwingRight() + +~~~~~ +SwingRight(corner) { + return Previous(Opposite(Previous(corner))); +} +~~~~~ + + +### SwingLeft() + +~~~~~ +SwingLeft(corner) { + return Next(Opposite(Next(corner))); +} +~~~~~ + + +### GetLeftCorner() + +~~~~~ +GetLeftCorner(corner_id) { + if (corner_id < 0) + return kInvalidCornerIndex; + return Opposite(Previous(corner_id)); +} +~~~~~ + + +### GetRightCorner() + +~~~~~ +GetRightCorner(corner_id) { + if (corner_id < 0) + return kInvalidCornerIndex; + return Opposite(Next(corner_id)); +} +~~~~~ + + +### SetOppositeCorner() + +~~~~~ +SetOppositeCorner(corner_id, pp_corner_id) { + opposite_corners_[corner_id] = opp_corner_id; +} +~~~~~ + + + +### 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; + } +} +~~~~~ + + +### 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; + } +} +~~~~~ + + + +### LeftMostCorner() + +~~~~~ +LeftMostCorner(v) { + return vertex_corners_[v]; +} +~~~~~ + + +### MakeVertexIsolated() + +~~~~~ +MakeVertexIsolated(vert) { + vertex_corners_[vert] = kInvalidCornerIndex; +} +~~~~~ + + + +## Mesh Attribute Corner Table + +### bool IsCornerOnSeam() + +~~~~~ +bool IsCornerOnSeam(corner) { + return is_vertex_on_seam_[corner_table_->Vertex(corner)]; +} +~~~~~ + + +### AddSeamEdge() + +~~~~~ +AddSeamEdge(c) { + MarkSeam(c) + opp_corner = corner_table_->Opposite(c); + if (opp_corner >= 0) { + no_interior_seams_ = false; + MarkSeam(opp_corner) + } +} +~~~~~ + + +### 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; +} +~~~~~ + + +### 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); + } + } +} +~~~~~ + + + + +## 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) + } +} +~~~~~ + + +### DecodeTaggedSymbols() + +~~~~~ +DecodeTaggedSymbols() { + FIXME +} +~~~~~ + + + +### DecodeRawSymbols() + +~~~~~ +DecodeRawSymbols() { + max_bit_length UI8 + DecodeRawSymbolsInternal(max_bit_length, out_values) + return symbols +} +~~~~~ + + + +### 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 + } +} +~~~~~ + + +### 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() +} +~~~~~ + + +### RansSymbolDecoder_StartDecoding() + +~~~~~ +RansSymbolDecoder_StartDecoding() { + bytes_encoded UI64 + buffer bytes_encoded * UI8 + rans_read_init(buffer, bytes_encoded) +} +~~~~~ + + + +### RansSymbolDecoder_DecodeSymbol() + +~~~~~ +RansSymbolDecoder_DecodeSymbol() { + ans_.rans_read() +} +~~~~~ + + +## 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; +} +~~~~~ + + + +### 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; +} +~~~~~ + + + +### 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; +} +~~~~~ + + + + +### 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 +} +~~~~~ + + + +### 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; +} +~~~~~ + + +### 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; +} +~~~~~ + + + +## 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) +} +~~~~~ + + +### DecodeNextBit() + +~~~~~ +DecodeNextBit() { + uint8_t bit = rabs_desc_read(&ans_decoder_, prob_zero_); + return bit > 0; +} +~~~~~ + + +## 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; +} +~~~~~ + + + +### ConvertSymbolToSignedInt() + +~~~~~ +ConvertSymbolToSignedInt() { + abs_val = val >> 1 + If (val & 1 == 0) { + return abs_val + } else { + signed_val = -abs_val - 1 + } + return signed_val +} +~~~~~ + + + +Sequential Decoder + +### 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 + } + } + } +} +~~~~~ diff --git a/docs/spec/index.md b/docs/spec/index.md new file mode 100644 index 0000000..b94da7f --- /dev/null +++ b/docs/spec/index.md @@ -0,0 +1,32 @@ +--- +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 %} + + +{% comment %} +{% include_relative 99.00.01.testing.md %} +{% endcomment %} diff --git a/docs/spec/mesh.decoder.md b/docs/spec/mesh.decoder.md new file mode 100644 index 0000000..c283bea --- /dev/null +++ b/docs/spec/mesh.decoder.md @@ -0,0 +1,11 @@ +## Mesh Decoder + +### DecodeConnectivityData() + +
      +DecodeConnectivityData() Type + InitializeDecoder() + DecodeConnectivity() +} + +
      From c2fb47ac5d6220bfbf8843f2f56e54bbdf2345aa Mon Sep 17 00:00:00 2001 From: Lou Quillio Date: Mon, 10 Jul 2017 14:36:26 -0700 Subject: [PATCH 2/4] Split syntax table sections into files. Also add .gitignore --- .gitignore | 1 + .ruby-version | 1 + docs/_config.yml | 1 + docs/_site/spec/00.00.03.last.modified.html | 2 +- docs/_site/spec/edgebreaker.decoder.html | 1206 --------------- docs/_site/spec/edgebreaker.decoder.md | 1312 ----------------- docs/_site/spec/index.html | 2 +- docs/spec/attributes.decoder.md | 20 + docs/spec/core.functions.md | 61 + docs/spec/corner.table.md | 197 +++ docs/spec/cornertable.traversal.processor.md | 40 + docs/spec/edgebreaker.decoder.md | 1312 ----------------- docs/spec/edgebreaker.hole.and.topology.md | 67 + docs/spec/edgebreaker.traversal.decoder.md | 44 + .../edgebreaker.traversal.valence.decoder.md | 88 ++ docs/spec/edgebreaker.traverser.md | 70 + docs/spec/index.md | 27 +- docs/spec/mesh.attribute.corner.table.md | 74 + ...esh.attribute.indices.encoding.observer.md | 17 + .../mesh.prediction.scheme.parallelogram.md | 58 + docs/spec/mesh.traversal.sequencer.md | 62 + docs/spec/prediction.scheme.transform.md | 14 + docs/spec/prediction.scheme.wrap.transform.md | 43 + docs/spec/rans.bit.decoder.md | 23 + docs/spec/rans.decoding.md | 120 ++ docs/spec/sequential.attribute.decoder.md | 26 + ...quential.attributes.decoders.controller.md | 52 + .../sequential.integer.attribute.decoder.md | 52 + ...quential.quantization.attribute.decoder.md | 46 + docs/spec/symbol.decoding.md | 105 ++ 30 files changed, 1305 insertions(+), 3838 deletions(-) create mode 100644 .gitignore create mode 100644 .ruby-version create mode 100644 docs/spec/attributes.decoder.md create mode 100644 docs/spec/core.functions.md create mode 100644 docs/spec/corner.table.md create mode 100644 docs/spec/cornertable.traversal.processor.md create mode 100644 docs/spec/edgebreaker.hole.and.topology.md create mode 100644 docs/spec/edgebreaker.traversal.decoder.md create mode 100644 docs/spec/edgebreaker.traversal.valence.decoder.md create mode 100644 docs/spec/edgebreaker.traverser.md create mode 100644 docs/spec/mesh.attribute.corner.table.md create mode 100644 docs/spec/mesh.attribute.indices.encoding.observer.md create mode 100644 docs/spec/mesh.prediction.scheme.parallelogram.md create mode 100644 docs/spec/mesh.traversal.sequencer.md create mode 100644 docs/spec/prediction.scheme.transform.md create mode 100644 docs/spec/prediction.scheme.wrap.transform.md create mode 100644 docs/spec/rans.bit.decoder.md create mode 100644 docs/spec/rans.decoding.md create mode 100644 docs/spec/sequential.attribute.decoder.md create mode 100644 docs/spec/sequential.attributes.decoders.controller.md create mode 100644 docs/spec/sequential.integer.attribute.decoder.md create mode 100644 docs/spec/sequential.quantization.attribute.decoder.md create mode 100644 docs/spec/symbol.decoding.md 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/_config.yml b/docs/_config.yml index 06dd47f..6c88dc6 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -30,5 +30,6 @@ gems: exclude: - Gemfile - Gemfile.lock + - docs/_site sass: style: compressed diff --git a/docs/_site/spec/00.00.03.last.modified.html b/docs/_site/spec/00.00.03.last.modified.html index 124fa6d..c73c61d 100644 --- a/docs/_site/spec/00.00.03.last.modified.html +++ b/docs/_site/spec/00.00.03.last.modified.html @@ -1,2 +1,2 @@ -

      Last modified: 2017-07-09 18:30:06 -0700

      +

      Last modified: 2017-07-10 14:30:06 -0700

      diff --git a/docs/_site/spec/edgebreaker.decoder.html b/docs/_site/spec/edgebreaker.decoder.html index d5a7db7..6dd5e50 100644 --- a/docs/_site/spec/edgebreaker.decoder.html +++ b/docs/_site/spec/edgebreaker.decoder.html @@ -348,1209 +348,3 @@ SetOppositeCorners(corner_0, corner_1) { Type - -

      EdgeBreaker Hole and Topology Split Events

      - -

      DecodeHoleAndTopologySplitEvents()

      - -

      FIXME: Escaping angle brackets

      - -
      -DecodeHoleAndTopologySplitEvents() { Type - num_topologoy_splits UI32 - source_symbol_id = 0 - for (i = 0; i < num_topologoy_splits; ++i) { - DecodeVarint\<UI32\>(&delta) - split_data[i].source_symbol_id = delta + source_symbol_id - DecodeVarint\<UI32\>(&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\<UI32\>(&delta) - hole_data[i].symbol_id = delta + symbol_id - } - return bytes_decoded; -} - -
      - -

      CreateAttributesDecoder

      - -

      FIXME: Escaping angle brackets

      - -
      -CreateAttributesDecoder() { Type - 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\<AttProcessor, AttObserver\> AttTraverser; - sequencer = CreateVertexTraversalSequencer\<AttTraverser\>(encoding_data); - } else if (traversal_method == MESH_TRAVERSAL_PREDICTION_DEGREE) { - typedef PredictionDegreeTraverser\<AttProcessor, AttObserver\> AttTraverser; - sequencer = CreateVertexTraversalSequencer\<AttTraverser\>(encoding_data); - } - } else { - // TODO - } - att_controller(new SequentialAttributeDecodersController(std::move(sequencer))) - decoder_->SetAttributesDecoder(att_decoder_id, std::move(att_controller)); -} - -
      - -

      Edgebreaker Traversal Decoder

      - -

      EdgebreakerTraversal_Start()

      - -
      -EdgebreakerTraversal_Start() { Type - size UI64 - symbol_buffer_ size * UI8 - size UI64 - start_face_buffer_ size * UI8 - if (num_attribute_data_ > 0) { - attribute_connectivity_decoders_ = std::unique_ptr<BinaryDecoder[]>( - new BinaryDecoder[num_attribute_data_]); - for (i = 0; i < num_attribute_data_; ++i) { - attribute_connectivity_decoders_[i].StartDecoding() - // RansBitDecoder_StartDecoding - } -} - -
      - -

      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
      -}
      -
      -
      - -

      DecodeAttributeSeam()

      - -
      DecodeAttributeSeam(int attribute) {
      -  return attribute_connectivity_decoders_[attribute].DecodeNextBit();
      -}
      -
      -
      - -

      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<UI32>(&num_symbols, out_buffer)
      -    If (num_symbols > 0) {
      -      DecodeSymbols(num_symbols, out_buffer, &context_symbols_[i])
      -    }
      -    context_counters_[i] = num_symbols
      -  }
      -  return out_buffer;
      -}
      -
      -
      - -

      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_
      -}
      -
      -
      - -

      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_);
      -}
      -
      -
      - -

      TraversalValence_MergeVertices()

      - -
      TraversalValence_MergeVertices(dest, source) {
      -  vertex_valences_[dest] += vertex_valences_[source];
      -}
      -
      -
      - -

      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;
      -}
      -
      -
      - -

      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))
      -}
      -
      -
      - -

      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()
      -  }
      -}
      -
      -
      - -

      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()
      -  }
      -}
      -
      -
      - -

      Sequential Attribute Decoder

      - -
      Initialize(...) {
      -  // Init some members
      -}
      -
      -
      - -

      DecodeValues()

      - -
      DecodeValues(const std::vector<PointIndex> &point_ids) {
      -  num_values = point_ids.size();
      -  entry_size = attribute_->byte_stride();
      -  std::unique_ptr<uint8_t[]> 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;
      -  }
      -}
      -
      -
      - -

      Sequential Integer Attribute Decoder

      - -
      Initialize(...) {
      -  SequentialAttributeDecoder_Initialize()
      -}
      -
      -
      - -

      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)
      -}
      -
      -
      - -

      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()
      -}
      -
      -
      - -

      Sequential Quantization Attribute Decoder

      - -
      Initialize(...) {
      -  SequentialIntegerAttributeDecoder_Initialize()
      -}
      -
      -
      - -

      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()
      -}
      -
      -
      - -

      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;
      -  }
      -}
      -
      -
      - -

      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];
      -  }
      -}
      -
      -
      - -

      Prediction Scheme Wrap Transform

      - -

      DecodeTransformData()

      - -
      DecodeTransformData(buffer) {
      -  min_value_                                                                 DT
      -  max_value_                                                                 DT
      -}
      -
      -
      - -

      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_;
      -    }
      -}
      -
      -
      - -

      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];
      -}
      -
      -
      - -

      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()
      -    }
      -  }
      -}
      -
      -
      - -

      MeshPredictionSchemeParallelogramShared

      - -

      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;
      -}
      -
      -
      - -

      CornerTable Traversal Processor

      - -

      IsFaceVisited()

      - -
      IsFaceVisited(corner_id) {
      -  if (corner_id < 0)
      -    return true
      -  return is_face_visited_[corner_id / 3];
      -}
      -
      -
      - -

      MarkFaceVisited()

      - -
      MarkFaceVisited(face_id) {
      -  is_face_visited_[face_id] = true;
      -}
      -
      -
      - -

      IsVertexVisited()

      - -
      IsVertexVisited(vert_id) {
      -  return is_vertex_visited_[vert_id];
      -}
      -
      -
      - -

      MarkVertexVisited()

      - -
      MarkVertexVisited(vert_id) {
      -  is_vertex_visited_[vert_id] = true;
      -}
      -
      -
      - -

      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++;
      -}
      -
      -
      - -

      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
      -        }
      -      }
      -    }
      -  }
      -}
      -
      -
      - -

      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();
      -}
      -
      -
      - -

      ProcessCorner()

      - -
      ProcessCorner(corner_id) {
      -  traverser_.TraverseFromCorner(corner_id);
      -}
      -
      -
      - -

      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);
      -    }
      -  }
      -}
      -
      -
      - -

      PointsSequencer

      - -

      AddPointId()

      - -
      AddPointId(point_id) {
      -  out_point_ids_->push_back(point_id);
      -}
      -
      -
      - -

      Corner Table

      - -

      Opposite()

      - -
      Opposite(corner) {
      -  return opposite_corners_[corner];
      -}
      -
      -
      - -

      Next()

      - -
      Next(corner) {
      -  return LocalIndex(++corner) ? corner : corner - 3;
      -}
      -
      -
      - -

      Previous()

      - -
      Previous(corner) {
      -  return LocalIndex(corner) ? corner - 1 : corner + 2;
      -}
      -
      -
      - -

      Vertex()

      - -
      Vertex(corner) {
      -  faces_[Face(corner)][LocalIndex(corner)];
      -}
      -
      -
      - -

      Face()

      - -
      Face(corner) {
      -  return corner / 3;
      -}
      -
      -
      - -

      LocalIndex()

      - -
      LocalIndex(corner) {
      -  return corner % 3;
      -}
      -
      -
      - -

      num_vertices()

      - -
      num_vertices() {
      -  return vertex_corners_.size();
      -}
      -
      -
      - -

      num_corners()

      - -
      num_corners() {
      -  return faces_.size() * 3;
      -}
      -
      -
      - -

      num_faces()

      - -
      num_faces() {
      -  return faces_.size();
      -}
      -
      -
      - -

      bool IsOnBoundary()

      - -
      bool IsOnBoundary(vert) {
      -  corner = LeftMostCorner(vert);
      -  if (SwingLeft(corner) < 0)
      -    return true;
      -  return false;
      -}
      -
      -
      - -

      SwingRight()

      - -
      SwingRight(corner) {
      -  return Previous(Opposite(Previous(corner)));
      -}
      -
      -
      - -

      SwingLeft()

      - -
      SwingLeft(corner) {
      -  return Next(Opposite(Next(corner)));
      -}
      -
      -
      - -

      GetLeftCorner()

      - -
      GetLeftCorner(corner_id) {
      -  if (corner_id < 0)
      -     return kInvalidCornerIndex;
      -  return Opposite(Previous(corner_id));
      -}
      -
      -
      - -

      GetRightCorner()

      - -
      GetRightCorner(corner_id) {
      -  if (corner_id < 0)
      -     return kInvalidCornerIndex;
      -  return Opposite(Next(corner_id));
      -}
      -
      -
      - -

      SetOppositeCorner()

      - -
      SetOppositeCorner(corner_id, pp_corner_id) {
      -  opposite_corners_[corner_id] = opp_corner_id;
      -}
      -
      -
      - -

      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;
      -  }
      -}
      -
      -
      - -

      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;
      -  }
      -}
      -
      -
      - -

      LeftMostCorner()

      - -
      LeftMostCorner(v) {
      -  return vertex_corners_[v];
      -}
      -
      -
      - -

      MakeVertexIsolated()

      - -
      MakeVertexIsolated(vert) {
      -  vertex_corners_[vert] = kInvalidCornerIndex;
      -}
      -
      -
      - -

      Mesh Attribute Corner Table

      - -

      bool IsCornerOnSeam()

      - -
      bool IsCornerOnSeam(corner) {
      -  return is_vertex_on_seam_[corner_table_->Vertex(corner)];
      -}
      -
      -
      - -

      AddSeamEdge()

      - -
      AddSeamEdge(c) {
      -  MarkSeam(c)
      -  opp_corner = corner_table_->Opposite(c);
      -  if (opp_corner >= 0) {
      -    no_interior_seams_ = false;
      -    MarkSeam(opp_corner)
      -  }
      -}
      -
      -
      - -

      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;
      -}
      -
      -
      - -

      RecomputeVertices()

      - -
      RecomputeVertices() {
      -  // in code RecomputeVerticesInternal<false>(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);
      -    }
      -  }
      -}
      -
      -
      - -

      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)
      -  }
      -}
      -
      -
      - -

      DecodeTaggedSymbols()

      - -
      DecodeTaggedSymbols() {
      -  FIXME
      -}
      -
      -
      - -

      DecodeRawSymbols()

      - -
      DecodeRawSymbols() {
      -  max_bit_length                                                             UI8
      -  DecodeRawSymbolsInternal(max_bit_length, out_values)
      -  return symbols
      -}
      -
      -
      - -

      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
      -  }
      -}
      -
      -
      - -

      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()
      -}
      -
      -
      - -

      RansSymbolDecoder_StartDecoding()

      - -
      RansSymbolDecoder_StartDecoding() {
      -  bytes_encoded                                                              UI64
      -  buffer                                                                     bytes_encoded * UI8
      -  rans_read_init(buffer, bytes_encoded)
      -}
      -
      -
      - -

      RansSymbolDecoder_DecodeSymbol()

      - -
      RansSymbolDecoder_DecodeSymbol() {
      -  ans_.rans_read()
      -}
      -
      -
      - -

      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;
      -}
      -
      -
      - -

      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;
      -}
      -
      -
      - -

      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;
      -}
      -
      -
      - -

      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
      -}
      -
      -
      - -

      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;
      -}
      -
      -
      - -

      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;
      -}
      -
      -
      - -

      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)
      -}
      -
      -
      - -

      DecodeNextBit()

      - -
      DecodeNextBit() {
      -  uint8_t bit = rabs_desc_read(&ans_decoder_, prob_zero_);
      -  return bit > 0;
      -}
      -
      -
      - -

      Core Functions

      - -

      DecodeVarint

      - -
      DecodeVarint<IT>() {
      -  If (std::is_unsigned<IT>::value) {
      -    in                                                                       UI8
      -    If (in & (1 << 7)) {
      -      out = DecodeVarint<IT>()
      -      out = (out << 7) | (in & ((1 << 7) - 1))
      -    } else {
      -      typename std::make_unsigned<IT>::type UIT;
      -      out = DecodeVarint<UIT>()
      -      out = ConvertSymbolToSignedInt(out)
      -    }
      -    return out;
      -}
      -
      -
      - -

      ConvertSymbolToSignedInt()

      - -
      ConvertSymbolToSignedInt() {
      -  abs_val = val >> 1
      -  If (val & 1 == 0) {
      -    return abs_val
      -  } else {
      -    signed_val = -abs_val - 1
      -  }
      -  return signed_val
      -}
      -
      -
      - -

      Sequential Decoder

      - -

      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
      -      }
      -    }
      -  }
      -}
      -
      -
      diff --git a/docs/_site/spec/edgebreaker.decoder.md b/docs/_site/spec/edgebreaker.decoder.md index 495901e..3536ec0 100644 --- a/docs/_site/spec/edgebreaker.decoder.md +++ b/docs/_site/spec/edgebreaker.decoder.md @@ -360,1315 +360,3 @@ SetOppositeCorners(corner_0, corner_1) { Type - - -## EdgeBreaker Hole and Topology Split Events - -### DecodeHoleAndTopologySplitEvents() - -FIXME: Escaping angle brackets - -
      -DecodeHoleAndTopologySplitEvents() { Type - 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; -} - -
      - -### CreateAttributesDecoder - -FIXME: Escaping angle brackets - -
      -CreateAttributesDecoder() { Type - 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)); -} - -
      - - -## Edgebreaker Traversal Decoder - -### EdgebreakerTraversal_Start() - -
      -EdgebreakerTraversal_Start() { Type - 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 - } -} - -
      - - -### 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 -} -~~~~~ - - -### DecodeAttributeSeam() - -~~~~~ -DecodeAttributeSeam(int attribute) { - return attribute_connectivity_decoders_[attribute].DecodeNextBit(); -} -~~~~~ - - -## 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; -} -~~~~~ - - - -### 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_ -} -~~~~~ - - - -### 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_); -} -~~~~~ - - - -### TraversalValence_MergeVertices() - -~~~~~ -TraversalValence_MergeVertices(dest, source) { - vertex_valences_[dest] += vertex_valences_[source]; -} -~~~~~ - - -## 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; -} -~~~~~ - - - -## 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)) -} -~~~~~ - - -### 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() - } -} -~~~~~ - - - -### 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() - } -} -~~~~~ - - -## Sequential Attribute Decoder - -~~~~~ -Initialize(...) { - // Init some members -} -~~~~~ - - -### 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; - } -} -~~~~~ - - -## Sequential Integer Attribute Decoder - -~~~~~ -Initialize(...) { - SequentialAttributeDecoder_Initialize() -} -~~~~~ - - -### 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) -} -~~~~~ - - -### 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() -} -~~~~~ - - - -## Sequential Quantization Attribute Decoder - -~~~~~ -Initialize(...) { - SequentialIntegerAttributeDecoder_Initialize() -} -~~~~~ - - -### 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() -} -~~~~~ - - -### 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; - } -} -~~~~~ - - - -## 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]; - } -} -~~~~~ - - - -## Prediction Scheme Wrap Transform - -### DecodeTransformData() - -~~~~~ -DecodeTransformData(buffer) { - min_value_ DT - max_value_ DT -} -~~~~~ - - -### 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_; - } -} -~~~~~ - - -### 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]; -} -~~~~~ - - - -## 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() - } - } -} -~~~~~ - - -MeshPredictionSchemeParallelogramShared - -### 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; -} -~~~~~ - - - -## CornerTable Traversal Processor - - -### IsFaceVisited() - -~~~~~ -IsFaceVisited(corner_id) { - if (corner_id < 0) - return true - return is_face_visited_[corner_id / 3]; -} -~~~~~ - - -### MarkFaceVisited() - -~~~~~ -MarkFaceVisited(face_id) { - is_face_visited_[face_id] = true; -} -~~~~~ - - -### IsVertexVisited() - -~~~~~ -IsVertexVisited(vert_id) { - return is_vertex_visited_[vert_id]; -} -~~~~~ - - -### MarkVertexVisited() - -~~~~~ -MarkVertexVisited(vert_id) { - is_vertex_visited_[vert_id] = true; -} -~~~~~ - - -## 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++; -} -~~~~~ - - -## 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 - } - } - } - } -} -~~~~~ - - -## 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(); -} -~~~~~ - - -### ProcessCorner() - -~~~~~ -ProcessCorner(corner_id) { - traverser_.TraverseFromCorner(corner_id); -} -~~~~~ - - -### 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); - } - } -} -~~~~~ - - -PointsSequencer - -### AddPointId() - -~~~~~ -AddPointId(point_id) { - out_point_ids_->push_back(point_id); -} -~~~~~ - - - -## Corner Table - -### Opposite() - -~~~~~ -Opposite(corner) { - return opposite_corners_[corner]; -} -~~~~~ - - -### Next() - -~~~~~ -Next(corner) { - return LocalIndex(++corner) ? corner : corner - 3; -} -~~~~~ - - -### Previous() - -~~~~~ -Previous(corner) { - return LocalIndex(corner) ? corner - 1 : corner + 2; -} -~~~~~ - - -### Vertex() - -~~~~~ -Vertex(corner) { - faces_[Face(corner)][LocalIndex(corner)]; -} -~~~~~ - - -### Face() - -~~~~~ -Face(corner) { - return corner / 3; -} -~~~~~ - - -### LocalIndex() - -~~~~~ -LocalIndex(corner) { - return corner % 3; -} -~~~~~ - - -### num_vertices() - -~~~~~ -num_vertices() { - return vertex_corners_.size(); -} -~~~~~ - - -### num_corners() - -~~~~~ -num_corners() { - return faces_.size() * 3; -} -~~~~~ - - -### num_faces() - -~~~~~ -num_faces() { - return faces_.size(); -} -~~~~~ - - -### bool IsOnBoundary() - -~~~~~ -bool IsOnBoundary(vert) { - corner = LeftMostCorner(vert); - if (SwingLeft(corner) < 0) - return true; - return false; -} -~~~~~ - - - -### SwingRight() - -~~~~~ -SwingRight(corner) { - return Previous(Opposite(Previous(corner))); -} -~~~~~ - - -### SwingLeft() - -~~~~~ -SwingLeft(corner) { - return Next(Opposite(Next(corner))); -} -~~~~~ - - -### GetLeftCorner() - -~~~~~ -GetLeftCorner(corner_id) { - if (corner_id < 0) - return kInvalidCornerIndex; - return Opposite(Previous(corner_id)); -} -~~~~~ - - -### GetRightCorner() - -~~~~~ -GetRightCorner(corner_id) { - if (corner_id < 0) - return kInvalidCornerIndex; - return Opposite(Next(corner_id)); -} -~~~~~ - - -### SetOppositeCorner() - -~~~~~ -SetOppositeCorner(corner_id, pp_corner_id) { - opposite_corners_[corner_id] = opp_corner_id; -} -~~~~~ - - - -### 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; - } -} -~~~~~ - - -### 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; - } -} -~~~~~ - - - -### LeftMostCorner() - -~~~~~ -LeftMostCorner(v) { - return vertex_corners_[v]; -} -~~~~~ - - -### MakeVertexIsolated() - -~~~~~ -MakeVertexIsolated(vert) { - vertex_corners_[vert] = kInvalidCornerIndex; -} -~~~~~ - - - -## Mesh Attribute Corner Table - -### bool IsCornerOnSeam() - -~~~~~ -bool IsCornerOnSeam(corner) { - return is_vertex_on_seam_[corner_table_->Vertex(corner)]; -} -~~~~~ - - -### AddSeamEdge() - -~~~~~ -AddSeamEdge(c) { - MarkSeam(c) - opp_corner = corner_table_->Opposite(c); - if (opp_corner >= 0) { - no_interior_seams_ = false; - MarkSeam(opp_corner) - } -} -~~~~~ - - -### 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; -} -~~~~~ - - -### 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); - } - } -} -~~~~~ - - - - -## 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) - } -} -~~~~~ - - -### DecodeTaggedSymbols() - -~~~~~ -DecodeTaggedSymbols() { - FIXME -} -~~~~~ - - - -### DecodeRawSymbols() - -~~~~~ -DecodeRawSymbols() { - max_bit_length UI8 - DecodeRawSymbolsInternal(max_bit_length, out_values) - return symbols -} -~~~~~ - - - -### 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 - } -} -~~~~~ - - -### 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() -} -~~~~~ - - -### RansSymbolDecoder_StartDecoding() - -~~~~~ -RansSymbolDecoder_StartDecoding() { - bytes_encoded UI64 - buffer bytes_encoded * UI8 - rans_read_init(buffer, bytes_encoded) -} -~~~~~ - - - -### RansSymbolDecoder_DecodeSymbol() - -~~~~~ -RansSymbolDecoder_DecodeSymbol() { - ans_.rans_read() -} -~~~~~ - - -## 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; -} -~~~~~ - - - -### 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; -} -~~~~~ - - - -### 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; -} -~~~~~ - - - - -### 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 -} -~~~~~ - - - -### 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; -} -~~~~~ - - -### 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; -} -~~~~~ - - - -## 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) -} -~~~~~ - - -### DecodeNextBit() - -~~~~~ -DecodeNextBit() { - uint8_t bit = rabs_desc_read(&ans_decoder_, prob_zero_); - return bit > 0; -} -~~~~~ - - -## 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; -} -~~~~~ - - - -### ConvertSymbolToSignedInt() - -~~~~~ -ConvertSymbolToSignedInt() { - abs_val = val >> 1 - If (val & 1 == 0) { - return abs_val - } else { - signed_val = -abs_val - 1 - } - return signed_val -} -~~~~~ - - - -Sequential Decoder - -### 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 - } - } - } -} -~~~~~ diff --git a/docs/_site/spec/index.html b/docs/_site/spec/index.html index 05d03ed..7013943 100644 --- a/docs/_site/spec/index.html +++ b/docs/_site/spec/index.html @@ -32,7 +32,7 @@ [author]
      [author]

      -

      Last modified: 2017-07-09 18:30:06 -0700

      +

      Last modified: 2017-07-10 14:30:06 -0700

      Abstract

      diff --git a/docs/spec/attributes.decoder.md b/docs/spec/attributes.decoder.md new file mode 100644 index 0000000..af4512a --- /dev/null +++ b/docs/spec/attributes.decoder.md @@ -0,0 +1,20 @@ + +## 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; +} +~~~~~ diff --git a/docs/spec/core.functions.md b/docs/spec/core.functions.md new file mode 100644 index 0000000..b86d93c --- /dev/null +++ b/docs/spec/core.functions.md @@ -0,0 +1,61 @@ + +## 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; +} +~~~~~ + + +### ConvertSymbolToSignedInt() + +~~~~~ +ConvertSymbolToSignedInt() { + abs_val = val >> 1 + If (val & 1 == 0) { + return abs_val + } else { + signed_val = -abs_val - 1 + } + return signed_val +} +~~~~~ + + +Sequential Decoder + +### 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 + } + } + } +} +~~~~~ diff --git a/docs/spec/corner.table.md b/docs/spec/corner.table.md new file mode 100644 index 0000000..4f37171 --- /dev/null +++ b/docs/spec/corner.table.md @@ -0,0 +1,197 @@ + +## Corner Table + +### Opposite() + +~~~~~ +Opposite(corner) { + return opposite_corners_[corner]; +} +~~~~~ + + +### Next() + +~~~~~ +Next(corner) { + return LocalIndex(++corner) ? corner : corner - 3; +} +~~~~~ + + +### Previous() + +~~~~~ +Previous(corner) { + return LocalIndex(corner) ? corner - 1 : corner + 2; +} +~~~~~ + + +### Vertex() + +~~~~~ +Vertex(corner) { + faces_[Face(corner)][LocalIndex(corner)]; +} +~~~~~ + + +### Face() + +~~~~~ +Face(corner) { + return corner / 3; +} +~~~~~ + + +### LocalIndex() + +~~~~~ +LocalIndex(corner) { + return corner % 3; +} +~~~~~ + + +### num_vertices() + +~~~~~ +num_vertices() { + return vertex_corners_.size(); +} +~~~~~ + + +### num_corners() + +~~~~~ +num_corners() { + return faces_.size() * 3; +} +~~~~~ + + +### num_faces() + +~~~~~ +num_faces() { + return faces_.size(); +} +~~~~~ + + +### bool IsOnBoundary() + +~~~~~ +bool IsOnBoundary(vert) { + corner = LeftMostCorner(vert); + if (SwingLeft(corner) < 0) + return true; + return false; +} +~~~~~ + + + +### SwingRight() + +~~~~~ +SwingRight(corner) { + return Previous(Opposite(Previous(corner))); +} +~~~~~ + + +### SwingLeft() + +~~~~~ +SwingLeft(corner) { + return Next(Opposite(Next(corner))); +} +~~~~~ + + +### GetLeftCorner() + +~~~~~ +GetLeftCorner(corner_id) { + if (corner_id < 0) + return kInvalidCornerIndex; + return Opposite(Previous(corner_id)); +} +~~~~~ + + +### GetRightCorner() + +~~~~~ +GetRightCorner(corner_id) { + if (corner_id < 0) + return kInvalidCornerIndex; + return Opposite(Next(corner_id)); +} +~~~~~ + + +### SetOppositeCorner() + +~~~~~ +SetOppositeCorner(corner_id, pp_corner_id) { + opposite_corners_[corner_id] = opp_corner_id; +} +~~~~~ + + + +### 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; + } +} +~~~~~ + + +### 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; + } +} +~~~~~ + + + +### LeftMostCorner() + +~~~~~ +LeftMostCorner(v) { + return vertex_corners_[v]; +} +~~~~~ + + +### MakeVertexIsolated() + +~~~~~ +MakeVertexIsolated(vert) { + vertex_corners_[vert] = kInvalidCornerIndex; +} +~~~~~ diff --git a/docs/spec/cornertable.traversal.processor.md b/docs/spec/cornertable.traversal.processor.md new file mode 100644 index 0000000..05b8390 --- /dev/null +++ b/docs/spec/cornertable.traversal.processor.md @@ -0,0 +1,40 @@ + +## CornerTable Traversal Processor + + +### IsFaceVisited() + +~~~~~ +IsFaceVisited(corner_id) { + if (corner_id < 0) + return true + return is_face_visited_[corner_id / 3]; +} +~~~~~ + + +### MarkFaceVisited() + +~~~~~ +MarkFaceVisited(face_id) { + is_face_visited_[face_id] = true; +} +~~~~~ + + +### IsVertexVisited() + +~~~~~ +IsVertexVisited(vert_id) { + return is_vertex_visited_[vert_id]; +} +~~~~~ + + +### MarkVertexVisited() + +~~~~~ +MarkVertexVisited(vert_id) { + is_vertex_visited_[vert_id] = true; +} +~~~~~ diff --git a/docs/spec/edgebreaker.decoder.md b/docs/spec/edgebreaker.decoder.md index 495901e..3536ec0 100644 --- a/docs/spec/edgebreaker.decoder.md +++ b/docs/spec/edgebreaker.decoder.md @@ -360,1315 +360,3 @@ SetOppositeCorners(corner_0, corner_1) { Type - - -## EdgeBreaker Hole and Topology Split Events - -### DecodeHoleAndTopologySplitEvents() - -FIXME: Escaping angle brackets - -
      -DecodeHoleAndTopologySplitEvents() { Type - 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; -} - -
      - -### CreateAttributesDecoder - -FIXME: Escaping angle brackets - -
      -CreateAttributesDecoder() { Type - 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)); -} - -
      - - -## Edgebreaker Traversal Decoder - -### EdgebreakerTraversal_Start() - -
      -EdgebreakerTraversal_Start() { Type - 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 - } -} - -
      - - -### 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 -} -~~~~~ - - -### DecodeAttributeSeam() - -~~~~~ -DecodeAttributeSeam(int attribute) { - return attribute_connectivity_decoders_[attribute].DecodeNextBit(); -} -~~~~~ - - -## 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; -} -~~~~~ - - - -### 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_ -} -~~~~~ - - - -### 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_); -} -~~~~~ - - - -### TraversalValence_MergeVertices() - -~~~~~ -TraversalValence_MergeVertices(dest, source) { - vertex_valences_[dest] += vertex_valences_[source]; -} -~~~~~ - - -## 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; -} -~~~~~ - - - -## 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)) -} -~~~~~ - - -### 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() - } -} -~~~~~ - - - -### 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() - } -} -~~~~~ - - -## Sequential Attribute Decoder - -~~~~~ -Initialize(...) { - // Init some members -} -~~~~~ - - -### 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; - } -} -~~~~~ - - -## Sequential Integer Attribute Decoder - -~~~~~ -Initialize(...) { - SequentialAttributeDecoder_Initialize() -} -~~~~~ - - -### 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) -} -~~~~~ - - -### 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() -} -~~~~~ - - - -## Sequential Quantization Attribute Decoder - -~~~~~ -Initialize(...) { - SequentialIntegerAttributeDecoder_Initialize() -} -~~~~~ - - -### 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() -} -~~~~~ - - -### 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; - } -} -~~~~~ - - - -## 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]; - } -} -~~~~~ - - - -## Prediction Scheme Wrap Transform - -### DecodeTransformData() - -~~~~~ -DecodeTransformData(buffer) { - min_value_ DT - max_value_ DT -} -~~~~~ - - -### 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_; - } -} -~~~~~ - - -### 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]; -} -~~~~~ - - - -## 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() - } - } -} -~~~~~ - - -MeshPredictionSchemeParallelogramShared - -### 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; -} -~~~~~ - - - -## CornerTable Traversal Processor - - -### IsFaceVisited() - -~~~~~ -IsFaceVisited(corner_id) { - if (corner_id < 0) - return true - return is_face_visited_[corner_id / 3]; -} -~~~~~ - - -### MarkFaceVisited() - -~~~~~ -MarkFaceVisited(face_id) { - is_face_visited_[face_id] = true; -} -~~~~~ - - -### IsVertexVisited() - -~~~~~ -IsVertexVisited(vert_id) { - return is_vertex_visited_[vert_id]; -} -~~~~~ - - -### MarkVertexVisited() - -~~~~~ -MarkVertexVisited(vert_id) { - is_vertex_visited_[vert_id] = true; -} -~~~~~ - - -## 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++; -} -~~~~~ - - -## 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 - } - } - } - } -} -~~~~~ - - -## 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(); -} -~~~~~ - - -### ProcessCorner() - -~~~~~ -ProcessCorner(corner_id) { - traverser_.TraverseFromCorner(corner_id); -} -~~~~~ - - -### 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); - } - } -} -~~~~~ - - -PointsSequencer - -### AddPointId() - -~~~~~ -AddPointId(point_id) { - out_point_ids_->push_back(point_id); -} -~~~~~ - - - -## Corner Table - -### Opposite() - -~~~~~ -Opposite(corner) { - return opposite_corners_[corner]; -} -~~~~~ - - -### Next() - -~~~~~ -Next(corner) { - return LocalIndex(++corner) ? corner : corner - 3; -} -~~~~~ - - -### Previous() - -~~~~~ -Previous(corner) { - return LocalIndex(corner) ? corner - 1 : corner + 2; -} -~~~~~ - - -### Vertex() - -~~~~~ -Vertex(corner) { - faces_[Face(corner)][LocalIndex(corner)]; -} -~~~~~ - - -### Face() - -~~~~~ -Face(corner) { - return corner / 3; -} -~~~~~ - - -### LocalIndex() - -~~~~~ -LocalIndex(corner) { - return corner % 3; -} -~~~~~ - - -### num_vertices() - -~~~~~ -num_vertices() { - return vertex_corners_.size(); -} -~~~~~ - - -### num_corners() - -~~~~~ -num_corners() { - return faces_.size() * 3; -} -~~~~~ - - -### num_faces() - -~~~~~ -num_faces() { - return faces_.size(); -} -~~~~~ - - -### bool IsOnBoundary() - -~~~~~ -bool IsOnBoundary(vert) { - corner = LeftMostCorner(vert); - if (SwingLeft(corner) < 0) - return true; - return false; -} -~~~~~ - - - -### SwingRight() - -~~~~~ -SwingRight(corner) { - return Previous(Opposite(Previous(corner))); -} -~~~~~ - - -### SwingLeft() - -~~~~~ -SwingLeft(corner) { - return Next(Opposite(Next(corner))); -} -~~~~~ - - -### GetLeftCorner() - -~~~~~ -GetLeftCorner(corner_id) { - if (corner_id < 0) - return kInvalidCornerIndex; - return Opposite(Previous(corner_id)); -} -~~~~~ - - -### GetRightCorner() - -~~~~~ -GetRightCorner(corner_id) { - if (corner_id < 0) - return kInvalidCornerIndex; - return Opposite(Next(corner_id)); -} -~~~~~ - - -### SetOppositeCorner() - -~~~~~ -SetOppositeCorner(corner_id, pp_corner_id) { - opposite_corners_[corner_id] = opp_corner_id; -} -~~~~~ - - - -### 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; - } -} -~~~~~ - - -### 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; - } -} -~~~~~ - - - -### LeftMostCorner() - -~~~~~ -LeftMostCorner(v) { - return vertex_corners_[v]; -} -~~~~~ - - -### MakeVertexIsolated() - -~~~~~ -MakeVertexIsolated(vert) { - vertex_corners_[vert] = kInvalidCornerIndex; -} -~~~~~ - - - -## Mesh Attribute Corner Table - -### bool IsCornerOnSeam() - -~~~~~ -bool IsCornerOnSeam(corner) { - return is_vertex_on_seam_[corner_table_->Vertex(corner)]; -} -~~~~~ - - -### AddSeamEdge() - -~~~~~ -AddSeamEdge(c) { - MarkSeam(c) - opp_corner = corner_table_->Opposite(c); - if (opp_corner >= 0) { - no_interior_seams_ = false; - MarkSeam(opp_corner) - } -} -~~~~~ - - -### 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; -} -~~~~~ - - -### 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); - } - } -} -~~~~~ - - - - -## 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) - } -} -~~~~~ - - -### DecodeTaggedSymbols() - -~~~~~ -DecodeTaggedSymbols() { - FIXME -} -~~~~~ - - - -### DecodeRawSymbols() - -~~~~~ -DecodeRawSymbols() { - max_bit_length UI8 - DecodeRawSymbolsInternal(max_bit_length, out_values) - return symbols -} -~~~~~ - - - -### 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 - } -} -~~~~~ - - -### 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() -} -~~~~~ - - -### RansSymbolDecoder_StartDecoding() - -~~~~~ -RansSymbolDecoder_StartDecoding() { - bytes_encoded UI64 - buffer bytes_encoded * UI8 - rans_read_init(buffer, bytes_encoded) -} -~~~~~ - - - -### RansSymbolDecoder_DecodeSymbol() - -~~~~~ -RansSymbolDecoder_DecodeSymbol() { - ans_.rans_read() -} -~~~~~ - - -## 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; -} -~~~~~ - - - -### 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; -} -~~~~~ - - - -### 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; -} -~~~~~ - - - - -### 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 -} -~~~~~ - - - -### 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; -} -~~~~~ - - -### 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; -} -~~~~~ - - - -## 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) -} -~~~~~ - - -### DecodeNextBit() - -~~~~~ -DecodeNextBit() { - uint8_t bit = rabs_desc_read(&ans_decoder_, prob_zero_); - return bit > 0; -} -~~~~~ - - -## 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; -} -~~~~~ - - - -### ConvertSymbolToSignedInt() - -~~~~~ -ConvertSymbolToSignedInt() { - abs_val = val >> 1 - If (val & 1 == 0) { - return abs_val - } else { - signed_val = -abs_val - 1 - } - return signed_val -} -~~~~~ - - - -Sequential Decoder - -### 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 - } - } - } -} -~~~~~ diff --git a/docs/spec/edgebreaker.hole.and.topology.md b/docs/spec/edgebreaker.hole.and.topology.md new file mode 100644 index 0000000..32f4fe1 --- /dev/null +++ b/docs/spec/edgebreaker.hole.and.topology.md @@ -0,0 +1,67 @@ + +## EdgeBreaker Hole and Topology Split Events + +### DecodeHoleAndTopologySplitEvents() + +FIXME: Escaping angle brackets + +
      +DecodeHoleAndTopologySplitEvents() { Type + 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; +} + +
      + +### CreateAttributesDecoder + +FIXME: Escaping angle brackets + +
      +CreateAttributesDecoder() { Type + 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)); +} + +
      + diff --git a/docs/spec/edgebreaker.traversal.decoder.md b/docs/spec/edgebreaker.traversal.decoder.md new file mode 100644 index 0000000..d1ee28e --- /dev/null +++ b/docs/spec/edgebreaker.traversal.decoder.md @@ -0,0 +1,44 @@ + +## Edgebreaker Traversal Decoder + +### EdgebreakerTraversal_Start() + +
      +EdgebreakerTraversal_Start() { Type + 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 + } +} + +
      + + +### 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 +} +~~~~~ + + +### DecodeAttributeSeam() + +~~~~~ +DecodeAttributeSeam(int attribute) { + return attribute_connectivity_decoders_[attribute].DecodeNextBit(); +} +~~~~~ diff --git a/docs/spec/edgebreaker.traversal.valence.decoder.md b/docs/spec/edgebreaker.traversal.valence.decoder.md new file mode 100644 index 0000000..a0d77f8 --- /dev/null +++ b/docs/spec/edgebreaker.traversal.valence.decoder.md @@ -0,0 +1,88 @@ + +## 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; +} +~~~~~ + + + +### 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_ +} +~~~~~ + + + +### 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_); +} +~~~~~ + + + +### TraversalValence_MergeVertices() + +~~~~~ +TraversalValence_MergeVertices(dest, source) { + vertex_valences_[dest] += vertex_valences_[source]; +} +~~~~~ diff --git a/docs/spec/edgebreaker.traverser.md b/docs/spec/edgebreaker.traverser.md new file mode 100644 index 0000000..3cf8f68 --- /dev/null +++ b/docs/spec/edgebreaker.traverser.md @@ -0,0 +1,70 @@ + +## 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 + } + } + } + } +} +~~~~~ diff --git a/docs/spec/index.md b/docs/spec/index.md index b94da7f..28c6157 100644 --- a/docs/spec/index.md +++ b/docs/spec/index.md @@ -13,18 +13,33 @@ version_date: Released 2017-xx-xx {% 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 %} diff --git a/docs/spec/mesh.attribute.corner.table.md b/docs/spec/mesh.attribute.corner.table.md new file mode 100644 index 0000000..3e0b7af --- /dev/null +++ b/docs/spec/mesh.attribute.corner.table.md @@ -0,0 +1,74 @@ + +## Mesh Attribute Corner Table + +### bool IsCornerOnSeam() + +~~~~~ +bool IsCornerOnSeam(corner) { + return is_vertex_on_seam_[corner_table_->Vertex(corner)]; +} +~~~~~ + + +### AddSeamEdge() + +~~~~~ +AddSeamEdge(c) { + MarkSeam(c) + opp_corner = corner_table_->Opposite(c); + if (opp_corner >= 0) { + no_interior_seams_ = false; + MarkSeam(opp_corner) + } +} +~~~~~ + + +### 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; +} +~~~~~ + + +### 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); + } + } +} +~~~~~ 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..6260cbe --- /dev/null +++ b/docs/spec/mesh.attribute.indices.encoding.observer.md @@ -0,0 +1,17 @@ + +## 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++; +} +~~~~~ diff --git a/docs/spec/mesh.prediction.scheme.parallelogram.md b/docs/spec/mesh.prediction.scheme.parallelogram.md new file mode 100644 index 0000000..9abf023 --- /dev/null +++ b/docs/spec/mesh.prediction.scheme.parallelogram.md @@ -0,0 +1,58 @@ + +## 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() + } + } +} +~~~~~ + + +MeshPredictionSchemeParallelogramShared + +### 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; +} +~~~~~ diff --git a/docs/spec/mesh.traversal.sequencer.md b/docs/spec/mesh.traversal.sequencer.md new file mode 100644 index 0000000..4e56f9f --- /dev/null +++ b/docs/spec/mesh.traversal.sequencer.md @@ -0,0 +1,62 @@ + +## 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(); +} +~~~~~ + + +### ProcessCorner() + +~~~~~ +ProcessCorner(corner_id) { + traverser_.TraverseFromCorner(corner_id); +} +~~~~~ + + +### 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); + } + } +} +~~~~~ + + +PointsSequencer + +### AddPointId() + +~~~~~ +AddPointId(point_id) { + out_point_ids_->push_back(point_id); +} +~~~~~ diff --git a/docs/spec/prediction.scheme.transform.md b/docs/spec/prediction.scheme.transform.md new file mode 100644 index 0000000..1745e27 --- /dev/null +++ b/docs/spec/prediction.scheme.transform.md @@ -0,0 +1,14 @@ + +## 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]; + } +} +~~~~~ diff --git a/docs/spec/prediction.scheme.wrap.transform.md b/docs/spec/prediction.scheme.wrap.transform.md new file mode 100644 index 0000000..e742adb --- /dev/null +++ b/docs/spec/prediction.scheme.wrap.transform.md @@ -0,0 +1,43 @@ + +## Prediction Scheme Wrap Transform + +### DecodeTransformData() + +~~~~~ +DecodeTransformData(buffer) { + min_value_ DT + max_value_ DT +} +~~~~~ + + +### 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_; + } +} +~~~~~ + + +### 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]; +} +~~~~~ diff --git a/docs/spec/rans.bit.decoder.md b/docs/spec/rans.bit.decoder.md new file mode 100644 index 0000000..17bb373 --- /dev/null +++ b/docs/spec/rans.bit.decoder.md @@ -0,0 +1,23 @@ + +## 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) +} +~~~~~ + + +### DecodeNextBit() + +~~~~~ +DecodeNextBit() { + uint8_t bit = rabs_desc_read(&ans_decoder_, prob_zero_); + return bit > 0; +} +~~~~~ diff --git a/docs/spec/rans.decoding.md b/docs/spec/rans.decoding.md new file mode 100644 index 0000000..358d506 --- /dev/null +++ b/docs/spec/rans.decoding.md @@ -0,0 +1,120 @@ + +## 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; +} +~~~~~ + + +### 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; +} +~~~~~ + + + +### 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; +} +~~~~~ + + +### 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 +} +~~~~~ + + + +### 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; +} +~~~~~ + + +### 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; +} +~~~~~ diff --git a/docs/spec/sequential.attribute.decoder.md b/docs/spec/sequential.attribute.decoder.md new file mode 100644 index 0000000..1461087 --- /dev/null +++ b/docs/spec/sequential.attribute.decoder.md @@ -0,0 +1,26 @@ + +## Sequential Attribute Decoder + +~~~~~ +Initialize(...) { + // Init some members +} +~~~~~ + + +### 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; + } +} +~~~~~ + diff --git a/docs/spec/sequential.attributes.decoders.controller.md b/docs/spec/sequential.attributes.decoders.controller.md new file mode 100644 index 0000000..fc7115f --- /dev/null +++ b/docs/spec/sequential.attributes.decoders.controller.md @@ -0,0 +1,52 @@ + +## 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)) +} +~~~~~ + + +### 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() + } +} +~~~~~ + + + +### 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() + } +} +~~~~~ + diff --git a/docs/spec/sequential.integer.attribute.decoder.md b/docs/spec/sequential.integer.attribute.decoder.md new file mode 100644 index 0000000..211007d --- /dev/null +++ b/docs/spec/sequential.integer.attribute.decoder.md @@ -0,0 +1,52 @@ + +## Sequential Integer Attribute Decoder + +~~~~~ +Initialize(...) { + SequentialAttributeDecoder_Initialize() +} +~~~~~ + + +### 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) +} +~~~~~ + + +### 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() +} +~~~~~ + diff --git a/docs/spec/sequential.quantization.attribute.decoder.md b/docs/spec/sequential.quantization.attribute.decoder.md new file mode 100644 index 0000000..0653cdc --- /dev/null +++ b/docs/spec/sequential.quantization.attribute.decoder.md @@ -0,0 +1,46 @@ + +## Sequential Quantization Attribute Decoder + +~~~~~ +Initialize(...) { + SequentialIntegerAttributeDecoder_Initialize() +} +~~~~~ + + +### 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() +} +~~~~~ + + +### 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; + } +} +~~~~~ diff --git a/docs/spec/symbol.decoding.md b/docs/spec/symbol.decoding.md new file mode 100644 index 0000000..2c71d1c --- /dev/null +++ b/docs/spec/symbol.decoding.md @@ -0,0 +1,105 @@ + +## 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) + } +} +~~~~~ + + +### DecodeTaggedSymbols() + +~~~~~ +DecodeTaggedSymbols() { + FIXME +} +~~~~~ + + + +### DecodeRawSymbols() + +~~~~~ +DecodeRawSymbols() { + max_bit_length UI8 + DecodeRawSymbolsInternal(max_bit_length, out_values) + return symbols +} +~~~~~ + + + +### 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 + } +} +~~~~~ + + +### 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() +} +~~~~~ + + +### RansSymbolDecoder_StartDecoding() + +~~~~~ +RansSymbolDecoder_StartDecoding() { + bytes_encoded UI64 + buffer bytes_encoded * UI8 + rans_read_init(buffer, bytes_encoded) +} +~~~~~ + + + +### RansSymbolDecoder_DecodeSymbol() + +~~~~~ +RansSymbolDecoder_DecodeSymbol() { + ans_.rans_read() +} +~~~~~ From 8d8c88e08f08d153364e6a4bc32f1f9ce065050b Mon Sep 17 00:00:00 2001 From: Lou Quillio Date: Wed, 12 Jul 2017 15:18:53 -0700 Subject: [PATCH 3/4] Re-org files, refine styles, add README, et al. Draco bitstream spec source should be ready for author contributions. --- docs/_site/assets/css/spec-style.css | 2 +- docs/_site/spec/00.00.03.last.modified.html | 2 +- docs/_site/spec/04.00.00.conventions.html | 50 ++ docs/_site/spec/04.00.00.conventions.md | 51 ++ docs/_site/spec/draco.decoder.html | 26 +- docs/_site/spec/draco.decoder.md | 35 +- docs/_site/spec/edgebreaker.decoder.html | 80 ++- docs/_site/spec/edgebreaker.decoder.md | 116 ++--- docs/_site/spec/index.html | 469 ++++++++++-------- docs/_site/spec/mesh.decoder.html | 5 +- docs/_site/spec/mesh.decoder.md | 8 +- docs/assets/css/spec-style.sass | 17 +- docs/index.md | 10 + docs/spec/04.00.00.conventions.md | 51 ++ docs/spec/README.md | 266 ++++++++++ docs/spec/attributes.decoder.md | 13 +- docs/spec/core.functions.md | 19 +- docs/spec/corner.table.md | 22 +- docs/spec/cornertable.traversal.processor.md | 4 + docs/spec/draco.decoder.md | 35 +- docs/spec/edgebreaker.decoder.md | 116 ++--- docs/spec/edgebreaker.hole.and.topology.md | 48 +- docs/spec/edgebreaker.traversal.decoder.md | 22 +- .../edgebreaker.traversal.valence.decoder.md | 11 +- docs/spec/edgebreaker.traverser.md | 1 + docs/spec/mesh.attribute.corner.table.md | 4 + ...esh.attribute.indices.encoding.observer.md | 1 + docs/spec/mesh.decoder.md | 8 +- .../mesh.prediction.scheme.parallelogram.md | 7 +- docs/spec/mesh.traversal.sequencer.md | 6 + docs/spec/prediction.scheme.transform.md | 5 +- docs/spec/prediction.scheme.wrap.transform.md | 11 +- docs/spec/rans.bit.decoder.md | 8 +- docs/spec/rans.decoding.md | 8 +- docs/spec/sequential.attribute.decoder.md | 4 +- ...quential.attributes.decoders.controller.md | 6 +- .../sequential.integer.attribute.decoder.md | 11 +- ...quential.quantization.attribute.decoder.md | 9 +- docs/spec/symbol.decoding.md | 24 +- 39 files changed, 1055 insertions(+), 536 deletions(-) create mode 100644 docs/index.md create mode 100644 docs/spec/README.md diff --git a/docs/_site/assets/css/spec-style.css b/docs/_site/assets/css/spec-style.css index 513a264..16d916f 100644 --- a/docs/_site/assets/css/spec-style.css +++ b/docs/_site/assets/css/spec-style.css @@ -1 +1 @@ -@import url("https://fonts.googleapis.com/css?family=Inconsolata");body{font-family:Arial,sans-serif;margin:10% 25% 10% 10%;line-height:1.3}a{color:navy;text-decoration:none}a:visited{color:navy;text-decoration:none}a:hover{text-decoration:underline}pre{font-family:"Inconsolata",monospace;border:2px solid #ddd;padding:1em;margin-left:1em;overflow-x:auto}code{font-family:"Inconsolata",monospace}table{border-collapse:collapse;min-width:50%;margin-left:1em}th,td{border:2px solid #ccc;padding:.5em}th{background-color:#333;color:#fff}table.terms th{display:none}table.terms td{vertical-align:top}table.conventions th{display:none}table.conventions td{vertical-align:top}table.conventions td:first-child{white-space:nowrap}table.nohead th{display:none}table.xyhead th,table.xyhead td:first-child{background-color:#9bbb59}table.xyhead th{color:#000;font-weight:normal}figure.highlight{background-color:#f2f2f2;padding-left:1em;padding-right:1em;border:2px solid #ccc}div.syntax{background-color:#fff;background-image:linear-gradient(90deg, transparent 540px, #abced4 540px, #abced4 542px, transparent 542px),linear-gradient(#ddd .1em, transparent .1em);background-size:100% 1.3em;border-left:2px solid #ddd;border-right:2px solid #ddd;border-bottom:2px solid #ddd;white-space:pre;font-family:"Inconsolata",monospace;font-size:1em;padding-left:1em;margin-left:1em;width:720px} +@import url("https://fonts.googleapis.com/css?family=Inconsolata");body{font-family:Arial,sans-serif;margin:10% 25% 10% 10%;line-height:1.3}a{color:navy;text-decoration:none}a:visited{color:navy;text-decoration:none}a:hover{text-decoration:underline}code{font-family:"Inconsolata",monospace}table{border-collapse:collapse;min-width:50%;margin-left:1em}th,td{border:2px solid #ccc;padding:.5em}th{background-color:#333;color:#fff}table.terms th{display:none}table.terms td{vertical-align:top}table.conventions th{display:none}table.conventions td{vertical-align:top}table.conventions td:first-child{white-space:nowrap}table.nohead th{display:none}table.xyhead th,table.xyhead td:first-child{background-color:#9bbb59}table.xyhead th{color:#000;font-weight:normal}figure.highlight{background-color:#f2f2f2;padding-left:1em;padding-right:1em;border:2px solid #ccc}div.draco-syntax pre{background-color:#fff;background-image:linear-gradient(90deg, transparent 580px, #abced4 580px, #abced4 582px, transparent 582px),linear-gradient(#ddd .1em, transparent .1em);background-size:100% 1.3em;border-left:2px solid #ddd;border-right:2px solid #ddd;border-bottom:2px solid #ddd;white-space:pre;font-family:"Inconsolata",monospace;font-size:1em;padding-left:1em;margin-left:1em;width:720px} diff --git a/docs/_site/spec/00.00.03.last.modified.html b/docs/_site/spec/00.00.03.last.modified.html index c73c61d..e39e03d 100644 --- a/docs/_site/spec/00.00.03.last.modified.html +++ b/docs/_site/spec/00.00.03.last.modified.html @@ -1,2 +1,2 @@ -

      Last modified: 2017-07-10 14:30:06 -0700

      +

      Last modified: 2017-07-12 15:15:50 -0700

      diff --git a/docs/_site/spec/04.00.00.conventions.html b/docs/_site/spec/04.00.00.conventions.html index 80fc2b5..0248e19 100644 --- a/docs/_site/spec/04.00.00.conventions.html +++ b/docs/_site/spec/04.00.00.conventions.html @@ -1,5 +1,7 @@

      Conventions

      +

      General Conventions

      +
      • When bit reading is finished it will always pad the read to the current @@ -40,3 +42,51 @@ first, then the connectivity section, and then the attribute section.

        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/_site/spec/04.00.00.conventions.md b/docs/_site/spec/04.00.00.conventions.md index 767de7c..762653f 100644 --- a/docs/_site/spec/04.00.00.conventions.md +++ b/docs/_site/spec/04.00.00.conventions.md @@ -1,5 +1,7 @@ ## Conventions +### General Conventions + * When bit reading is finished it will always pad the read to the current byte. @@ -24,3 +26,52 @@ * 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/_site/spec/draco.decoder.html b/docs/_site/spec/draco.decoder.html index 114ff0c..d70d8b5 100644 --- a/docs/_site/spec/draco.decoder.html +++ b/docs/_site/spec/draco.decoder.html @@ -2,33 +2,30 @@

      Decode()

      -
      -Decode() { Type +
      Decode() {
         DecodeHeader()
         DecodeConnectivityData()
         DecodeAttributeData()}
      -
      +

      DecodeHeader()

      -
      -DecodeHeader() { Type - draco_string UI8[5] - major_version UI8 - minor_version UI8 - encoder_type UI8 - encoder_method UI8 +
      DecodeHeader() {
      +  draco_string                                                          UI8[5]
      +  major_version                                                         UI8
      +  minor_version                                                         UI8
      +  encoder_type                                                          UI8
      +  encoder_method                                                        UI8
         flags
       }
      -
      +

      DecodeAttributeData()

      -
      -DecodeAttributeData() { Type - num_attributes_decoders UI8 +
      DecodeAttributeData() {
      +  num_attributes_decoders                                               UI8
         for (i = 0; i < num_attributes_decoders; ++i) {
           CreateAttributesDecoder(i);
         }
      @@ -40,4 +37,5 @@ DecodeAttributeData() {                                               Type
      diff --git a/docs/_site/spec/draco.decoder.md b/docs/_site/spec/draco.decoder.md index 99c8096..7cb3cc5 100644 --- a/docs/_site/spec/draco.decoder.md +++ b/docs/_site/spec/draco.decoder.md @@ -2,35 +2,35 @@ ### Decode() -
      -Decode() { Type +~~~~~ +Decode() { DecodeHeader() DecodeConnectivityData() DecodeAttributeData()} - -
      +~~~~~ +{:.draco-syntax} ### DecodeHeader() -
      -DecodeHeader() { Type - draco_string UI8[5] - major_version UI8 - minor_version UI8 - encoder_type UI8 - encoder_method UI8 +~~~~~ +DecodeHeader() { + draco_string UI8[5] + major_version UI8 + minor_version UI8 + encoder_type UI8 + encoder_method UI8 flags } - -
      +~~~~~ +{:.draco-syntax} ### DecodeAttributeData() -
      -DecodeAttributeData() { Type - num_attributes_decoders UI8 +~~~~~ +DecodeAttributeData() { + num_attributes_decoders UI8 for (i = 0; i < num_attributes_decoders; ++i) { CreateAttributesDecoder(i); } @@ -42,4 +42,5 @@ DecodeAttributeData() { Type +~~~~~ +{:.draco-syntax} diff --git a/docs/_site/spec/edgebreaker.decoder.html b/docs/_site/spec/edgebreaker.decoder.html index 6dd5e50..ec8e5ee 100644 --- a/docs/_site/spec/edgebreaker.decoder.html +++ b/docs/_site/spec/edgebreaker.decoder.html @@ -2,25 +2,24 @@

      InitializeDecoder()

      -
      -InitializeDecoder() { Type - edgebreaker_decoder_type UI8 +
      InitializeDecoder() {
      +  edgebreaker_decoder_type                                              UI8
       }
      -
      +

      DecodeConnectivity()

      -
      -DecodeConnectivity() { Type - 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 +
      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()
      @@ -46,13 +45,12 @@ DecodeConnectivity() {                                                Type

      AssignPointsToCorners()

      -
      -AssignPointsToCorners() { Type +
      AssignPointsToCorners() {
         decoder_->mesh()->SetNumFaces(corner_table_->num_faces());
         if (attribute_data_.size() == 0) {
           for (f = 0; f < decoder_->mesh()->num_faces(); ++f) {
      @@ -123,13 +121,12 @@ AssignPointsToCorners() {                                             Type

      DecodeConnectivity()

      -
      -DecodeConnectivity(num_symbols) { Type +
      DecodeConnectivity(num_symbols) {
         for (i = 0; i < num_symbols; ++i) {
           symbol = TraversalValence_DecodeSymbol()
           corner = 3 * num_faces++
      @@ -184,13 +181,12 @@ DecodeConnectivity(num_symbols) {                                     Type

      UpdateCornerTableForSymbolC()

      -
      -UpdateCornerTableForSymbolC(corner) { Type +
      UpdateCornerTableForSymbolC(corner) {
         corner_a = active_corner_stack.back();
         corner_b = corner_table_->Previous(corner_a);
         while (corner_table_->Opposite(corner_b) >= 0) {
      @@ -206,13 +202,12 @@ UpdateCornerTableForSymbolC(corner) {                                 Type

      UpdateCornerTableForSymbolLR()

      -
      -UpdateCornerTableForSymbolLR(corner, symbol) { Type +
      UpdateCornerTableForSymbolLR(corner, symbol) {
         if (symbol == TOPOLOGY_R) {
           opp_corner = corner + 2;
         } else {
      @@ -227,13 +222,12 @@ UpdateCornerTableForSymbolLR(corner, symbol) {                        Type

      HandleSymbolS()

      -
      -HandleSymbolS(corner) { Type +
      HandleSymbolS(corner) {
         corner_b = active_corner_stack.pop_back();
         it = topology_split_active_corners.find(symbol_id);
         if (it != topology_split_active_corners.end()) {
      @@ -258,24 +252,22 @@ HandleSymbolS(corner) {                                               Type

      UpdateCornerTableForSymbolE()

      -
      -UpdateCornerTableForSymbolE() { Type +
      UpdateCornerTableForSymbolE() {
         corner_table_->MapCornerToVertex(corner, num_vertices++);
         corner_table_->MapCornerToVertex(corner + 1, num_vertices++);
         corner_table_->MapCornerToVertex(corner + 2, num_vertices++);
       }
      -
      +

      UpdateCornerTableForInteriorFace()

      -
      -UpdateCornerTableForInteriorFace() { Type +
      UpdateCornerTableForInteriorFace() {
         corner_b = corner_table_->Previous(corner);
         while (corner_table_->Opposite(corner_b) >= 0) {
           corner_b = corner_table_->Previous(corner_table_->Opposite(corner_b));
      @@ -292,14 +284,12 @@ UpdateCornerTableForInteriorFace() {                                  Type

      IsTopologySplit()

      -
      -IsTopologySplit(encoder_symbol_id, *out_face_edge, Type - +
      IsTopologySplit(encoder_symbol_id, *out_face_edge,
                                *out_encoder_split_symbol_id) {
         if (topology_split_data_.size() == 0)
           return false;
      @@ -311,13 +301,12 @@ IsTopologySplit(encoder_symbol_id, *out_face_edge,                    Type

      DecodeAttributeConnectivitiesOnFace()

      -
      -DecodeAttributeConnectivitiesOnFace(corner) { Type +
      DecodeAttributeConnectivitiesOnFace(corner) {
         corners[3] = {corner, corner_table_->Next(corner),
                              corner_table_->Previous(corner)}
         for (c = 0; c < 3; ++c) {
      @@ -336,15 +325,14 @@ DecodeAttributeConnectivitiesOnFace(corner) {                         Type

      SetOppositeCorners()

      -
      -SetOppositeCorners(corner_0, corner_1) { Type +
      SetOppositeCorners(corner_0, corner_1) {
         corner_table_->SetOppositeCorner(corner_0, corner_1);
         corner_table_->SetOppositeCorner(corner_1, corner_0);
       }
      -
      +
      diff --git a/docs/_site/spec/edgebreaker.decoder.md b/docs/_site/spec/edgebreaker.decoder.md index 3536ec0..11baa85 100644 --- a/docs/_site/spec/edgebreaker.decoder.md +++ b/docs/_site/spec/edgebreaker.decoder.md @@ -2,26 +2,27 @@ ### InitializeDecoder() -
      -InitializeDecoder() { Type - edgebreaker_decoder_type UI8 +~~~~~ +InitializeDecoder() { + edgebreaker_decoder_type UI8 } - -
      +~~~~~ +{:.draco-syntax } ### DecodeConnectivity() -
      -DecodeConnectivity() { Type - 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 +~~~~~ +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() @@ -47,14 +48,14 @@ DecodeConnectivity() { Type +~~~~~ +{:.draco-syntax } ### AssignPointsToCorners() -
      -AssignPointsToCorners() { Type +~~~~~ +AssignPointsToCorners() { decoder_->mesh()->SetNumFaces(corner_table_->num_faces()); if (attribute_data_.size() == 0) { for (f = 0; f < decoder_->mesh()->num_faces(); ++f) { @@ -125,14 +126,14 @@ AssignPointsToCorners() { Typepoint_cloud()->set_num_points(point_to_corner_map.size()); } - -
      +~~~~~ +{:.draco-syntax } ### DecodeConnectivity() -
      -DecodeConnectivity(num_symbols) { Type +~~~~~ +DecodeConnectivity(num_symbols) { for (i = 0; i < num_symbols; ++i) { symbol = TraversalValence_DecodeSymbol() corner = 3 * num_faces++ @@ -187,14 +188,14 @@ DecodeConnectivity(num_symbols) { Type +~~~~~ +{:.draco-syntax } ### UpdateCornerTableForSymbolC() -
      -UpdateCornerTableForSymbolC(corner) { Type +~~~~~ +UpdateCornerTableForSymbolC(corner) { corner_a = active_corner_stack.back(); corner_b = corner_table_->Previous(corner_a); while (corner_table_->Opposite(corner_b) >= 0) { @@ -210,15 +211,15 @@ UpdateCornerTableForSymbolC(corner) { TypeVertex(corner_table_->Previous(corner_a))); return vertex_x; } - -
      +~~~~~ +{:.draco-syntax } ### UpdateCornerTableForSymbolLR() -
      -UpdateCornerTableForSymbolLR(corner, symbol) { Type +~~~~~ +UpdateCornerTableForSymbolLR(corner, symbol) { if (symbol == TOPOLOGY_R) { opp_corner = corner + 2; } else { @@ -233,14 +234,14 @@ UpdateCornerTableForSymbolLR(corner, symbol) { TypePrevious(opp_corner), corner_table_->Vertex(corner_table_->Next(corner_a))); } - -
      +~~~~~ +{:.draco-syntax } ### HandleSymbolS() -
      -HandleSymbolS(corner) { Type +~~~~~ +HandleSymbolS(corner) { corner_b = active_corner_stack.pop_back(); it = topology_split_active_corners.find(symbol_id); if (it != topology_split_active_corners.end()) { @@ -265,26 +266,26 @@ HandleSymbolS(corner) { TypeMakeVertexIsolated(vertex_n); } - -
      +~~~~~ +{:.draco-syntax } ### UpdateCornerTableForSymbolE() -
      -UpdateCornerTableForSymbolE() { Type +~~~~~ +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() { Type +~~~~~ +UpdateCornerTableForInteriorFace() { corner_b = corner_table_->Previous(corner); while (corner_table_->Opposite(corner_b) >= 0) { corner_b = corner_table_->Previous(corner_table_->Opposite(corner_b)); @@ -301,15 +302,14 @@ UpdateCornerTableForInteriorFace() { TypeMapCornerToVertex( new_corner + 2, corner_table_->Vertex(corner_table_->Next(corner))); } - -
      +~~~~~ +{:.draco-syntax } ### IsTopologySplit() -
      -IsTopologySplit(encoder_symbol_id, *out_face_edge, Type - +~~~~~ +IsTopologySplit(encoder_symbol_id, *out_face_edge, *out_encoder_split_symbol_id) { if (topology_split_data_.size() == 0) return false; @@ -321,14 +321,14 @@ IsTopologySplit(encoder_symbol_id, *out_face_edge, Type +~~~~~ +{:.draco-syntax } ### DecodeAttributeConnectivitiesOnFace() -
      -DecodeAttributeConnectivitiesOnFace(corner) { Type +~~~~~ +DecodeAttributeConnectivitiesOnFace(corner) { corners[3] = {corner, corner_table_->Next(corner), corner_table_->Previous(corner)} for (c = 0; c < 3; ++c) { @@ -347,16 +347,16 @@ DecodeAttributeConnectivitiesOnFace(corner) { Type +~~~~~ +{:.draco-syntax } ### SetOppositeCorners() -
      -SetOppositeCorners(corner_0, corner_1) { Type +~~~~~ +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/_site/spec/index.html b/docs/_site/spec/index.html index 7013943..76b6bd1 100644 --- a/docs/_site/spec/index.html +++ b/docs/_site/spec/index.html @@ -32,7 +32,7 @@ [author]
      [author]

      -

      Last modified: 2017-07-10 14:30:06 -0700

      +

      Last modified: 2017-07-12 15:15:50 -0700

      Abstract

      @@ -45,7 +45,11 @@ Draco 3D Data Compression scheme.

    • Scope
    • Terms and Definitions
    • Symbols (and abbreviated terms)
    • -
    • Conventions
    • +
    • Conventions +
    • Draco Decoder