frosix

Multiparty signature service (experimental)
Log | Files | Refs | README | LICENSE

commit a28843925368e35572559c969c0555c925586126
Author: Joel Urech <joeltobias.urech@students.bfh.ch>
Date:   Thu, 15 Jun 2023 17:53:58 +0200

initial commit

Diffstat:
AAUTHORS | 3+++
ACOPYING | 661+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AChangeLog | 0
AINSTALL | 368+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AMakefile.am | 6++++++
ANEWS | 0
AREADME | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abootstrap | 35+++++++++++++++++++++++++++++++++++
Aconfigure.ac | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/Makefile.am | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/microhttpd.tag | 182+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/pp/README | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/pp/conf.py | 282+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/pp/en/0.epub | 0
Acontrib/pp/en/0.html | 189+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/pp/en/0.pdf | 0
Acontrib/pp/en/0.txt | 219+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/pp/en/0.xml | 177+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/pp/locale/de/LC_MESSAGES/pp.po | 511+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/pp/pp.rst | 224+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/provider-list.json | 38++++++++++++++++++++++++++++++++++++++
Acontrib/tos/README | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/tos/conf.py | 282+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/tos/en/0.epub | 0
Acontrib/tos/en/0.html | 273+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/tos/en/0.pdf | 0
Acontrib/tos/en/0.txt | 287+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/tos/en/0.xml | 271+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/tos/locale/de/LC_MESSAGES/tos.po | 517+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/tos/tos.rst | 265+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/uncrustify.cfg | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/uncrustify_precommit | 35+++++++++++++++++++++++++++++++++++
Adoc/Makefile.am | 4++++
Adoc/bachelor-thesis/README.md | 215+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/content/.gitkeep | 0
Adoc/bachelor-thesis/content/abstract.tex | 19+++++++++++++++++++
Adoc/bachelor-thesis/content/acknowledgements.tex | 13+++++++++++++
Adoc/bachelor-thesis/content/design.tex | 526+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/content/future_work.tex | 31+++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/content/glossary.tex | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/content/implementation.tex | 668+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/content/introduction.tex | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/content/project_plan.tex | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/content/related_work.tex | 436+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/figures/.gitkeep | 0
Adoc/bachelor-thesis/figures/DKG-Combined.svg | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/figures/DKG-Parties.svg | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/figures/DKG-Threshold.svg | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/figures/Frosix_JoelUrech.pdf | 0
Adoc/bachelor-thesis/figures/Sign-Client.svg | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/figures/Sign-Provider.svg | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/figures/Verify-Client.svg | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/figures/frosix_client_authentication_hash.png | 0
Adoc/bachelor-thesis/figures/frosix_client_authentication_hash_question.png | 0
Adoc/bachelor-thesis/figures/frosix_client_entropy.png | 0
Adoc/bachelor-thesis/figures/frosix_database.png | 0
Adoc/bachelor-thesis/figures/frosix_delete-key_sequence.png | 0
Adoc/bachelor-thesis/figures/frosix_dkg_sequence.png | 0
Adoc/bachelor-thesis/figures/frosix_entropy_figures_legend.drawio | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/figures/frosix_entropy_figures_legend.png | 0
Adoc/bachelor-thesis/figures/frosix_perf_dkg_combined.png | 0
Adoc/bachelor-thesis/figures/frosix_perf_dkg_parties.png | 0
Adoc/bachelor-thesis/figures/frosix_perf_dkg_threshold.png | 0
Adoc/bachelor-thesis/figures/frosix_perf_sign_client.png | 0
Adoc/bachelor-thesis/figures/frosix_perf_sign_provider.png | 0
Adoc/bachelor-thesis/figures/frosix_perf_verify_client.png | 0
Adoc/bachelor-thesis/figures/frosix_provider_dkg-commitment_entropy.png | 0
Adoc/bachelor-thesis/figures/frosix_provider_dkg-key_entropy.png | 0
Adoc/bachelor-thesis/figures/frosix_provider_sign_entropy.png | 0
Adoc/bachelor-thesis/figures/frosix_request-challenge_sequence.png | 0
Adoc/bachelor-thesis/figures/frosix_server_architecture.png | 0
Adoc/bachelor-thesis/figures/frosix_sign_sequence.png | 0
Adoc/bachelor-thesis/figures/frosix_system_architecture.png | 0
Adoc/bachelor-thesis/figures/frosix_system_overview.png | 0
Adoc/bachelor-thesis/frosix.glg | 7+++++++
Adoc/bachelor-thesis/frosix.gls | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/frosix.pdf | 0
Adoc/bachelor-thesis/frosix.tex | 216+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/bachelor-thesis/frosix.tex.bbl | 0
Adoc/bachelor-thesis/frosix.tex.blg | 5+++++
Adoc/bachelor-thesis/listings/.gitkeep | 0
Adoc/bachelor-thesis/pictures/.gitkeep | 0
Adoc/bachelor-thesis/pictures/frosix_logo.png | 0
Adoc/bachelor-thesis/pictures/project_planning.png | 0
Adoc/bachelor-thesis/project.bib | 522+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/doxygen/Makefile.am | 11+++++++++++
Adoc/doxygen/frosix.doxy | 303+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/Makefile | 191+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/README | 14++++++++++++++
Adoc/sphinx/_exts/__pycache__/ebicsdomain.cpython-310.pyc | 0
Adoc/sphinx/_exts/__pycache__/typescriptdomain.cpython-310.pyc | 0
Adoc/sphinx/_exts/ebicsdomain.py | 229+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/httpdomain/__init__.py | 14++++++++++++++
Adoc/sphinx/_exts/httpdomain/__pycache__/__init__.cpython-310.pyc | 0
Adoc/sphinx/_exts/httpdomain/__pycache__/httpdomain.cpython-310.pyc | 0
Adoc/sphinx/_exts/httpdomain/autohttp/__init__.py | 11+++++++++++
Adoc/sphinx/_exts/httpdomain/autohttp/bottle.py | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/httpdomain/autohttp/common.py | 36++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/httpdomain/autohttp/flask.py | 48++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/httpdomain/autohttp/flask_base.py | 215+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/httpdomain/autohttp/flaskqref.py | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/httpdomain/autohttp/tornado.py | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/httpdomain/httpdomain.py | 773+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/__init__.py | 166+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/__pycache__/__init__.cpython-310.pyc | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/comments.html | 16++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/globaltoc.html | 14++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/layout.html | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/localtoc.html | 10++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/logo-text.html | 1+
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/search.html | 48++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/searchbox.html | 15+++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/css/bootstrap-theme.min.css | 8++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/css/bootstrap.min.css | 8++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.svg | 230+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.svg | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.svg | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.svg | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.svg | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.svg | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.svg | 253+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.svg | 253+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.svg | 253+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.svg | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.svg | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/stylesheet.css | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Black.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Bold.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-ExtraLight.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Light.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Regular.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Semibold.eot | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/LICENSE.txt | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Black.otf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Bold.otf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-ExtraLight.otf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Light.otf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Regular.otf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Semibold.otf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/README.md | 18++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/ReadMe.html | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/SourceSerifProReadMe.html | 189+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Black.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Bold.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-ExtraLight.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Light.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Regular.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Semibold.ttf | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Black.otf.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Bold.otf.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-ExtraLight.otf.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Light.otf.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Regular.otf.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Semibold.otf.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Black.ttf.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Bold.ttf.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-ExtraLight.ttf.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Light.ttf.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Regular.ttf.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Semibold.ttf.woff | 0
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/bower.json | 15+++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/source-serif-pro.css | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/guzzle.css_t | 1037+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/jquery.js | 5+++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/jquery.min.map | 2++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/js/bootstrap.js | 1952+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/js/bootstrap.min.js | 7+++++++
Adoc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/theme.conf | 40++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/_exts/typescriptdomain.py | 587+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/appendix.rst | 29+++++++++++++++++++++++++++++
Adoc/sphinx/conf.py | 307+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/fdl-1.3.rst | 453+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/index.rst | 40++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/introduction.rst | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/libfrost.rst | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/rest.rst | 750+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/sphinx/sources.rst | 33+++++++++++++++++++++++++++++++++
Asrc/Makefile.am | 3+++
Asrc/authorization/Makefile.am | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/authorization/frosix_authorization_plugin.c | 227+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/authorization/frosix_authorization_plugin_file.c | 326+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/Makefile.am | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd.c | 1196+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd.h | 232+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_auth-challenge.c | 449+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_auth.h | 38++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_common.c | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_config.c | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_config.h | 41+++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_dkg-commitment.c | 380+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_dkg-key.c | 739+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_dkg-key_delete.c | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_dkg-shares.c | 669+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_dkg.h | 143+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_mhd.c | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_mhd.h | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_seed.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_seed.h | 40++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_sig-commitment.c | 573+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_sig-share.c | 447+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_sig.h | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_terms.c | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix-httpd_terms.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/frosix.conf | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cli/Makefile.am | 39+++++++++++++++++++++++++++++++++++++++
Asrc/cli/frosix-cli-redux.c | 568+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cli/test-frosix.sh | 163+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cli/test-frosix_1.conf | 20++++++++++++++++++++
Asrc/cli/test-frosix_2.conf | 20++++++++++++++++++++
Asrc/cli/test-frosix_3.conf | 20++++++++++++++++++++
Asrc/cli/test-frosix_4.conf | 20++++++++++++++++++++
Asrc/cli/test-frosix_5.conf | 20++++++++++++++++++++
Asrc/cli/test-frosix_providerlist.json | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/frosixdb/Makefile.am | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/frosixdb/drop.sql | 25+++++++++++++++++++++++++
Asrc/frosixdb/frosix-0001.sql | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/frosixdb/frosix-dbinit.c | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/frosixdb/frosix_db_plugin.c | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/frosixdb/frosix_db_postgres.conf | 7+++++++
Asrc/frosixdb/plugin_frosix_postgres.c | 1489+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/frosixdb/versioning.sql | 293+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/Makefile.am | 19+++++++++++++++++++
Asrc/include/frosix.h | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/frosix_authorization_lib.h | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/frosix_authorization_plugin.h | 280+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/frosix_backend.h | 257+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/frosix_crypto.h | 439+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/frosix_database_lib.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/frosix_database_plugin.h | 736+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/frosix_service.h | 1187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/frosix_util_lib.h | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/frost_high.h | 323+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/frost_low.h | 451+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/frost_verify.h | 44++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/gettext.h | 311+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/keygen.h | 269+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/platform.h | 289++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrosix/Makefile.am | 32++++++++++++++++++++++++++++++++
Asrc/libfrosix/frosix_api.c | 320+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrosix/frosix_api.h | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrosix/frosix_api_delete-key.c | 341+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrosix/frosix_api_keygen.c | 1279+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrosix/frosix_api_request-challenge.c | 396+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrosix/frosix_api_sign.c | 793+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrostdistkeygen/Makefile.am | 19+++++++++++++++++++
Asrc/libfrostdistkeygen/dkg_commitment.c | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrostdistkeygen/keygen_begin.c | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrostdistkeygen/keygen_common.c | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrostdistkeygen/keygen_common.h | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrostdistkeygen/keygen_finalize.c | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrostdistkeygen/keygen_validate_commitment.c | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrostdistkeygen/keygen_validate_share.c | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrostdistkeygen/validate_params.c | 39+++++++++++++++++++++++++++++++++++++++
Asrc/libfrosthigh/Makefile.am | 42++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrosthigh/compose_signature.c | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrosthigh/frost_init.c | 33+++++++++++++++++++++++++++++++++
Asrc/libfrosthigh/generate_commitment.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrosthigh/high_common.c | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrosthigh/high_common.h | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrosthigh/message_to_hash.c | 37+++++++++++++++++++++++++++++++++++++
Asrc/libfrosthigh/sign_message_hash.c | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrosthigh/test_frost.c | 264+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrosthigh/validate_commitments.c | 35+++++++++++++++++++++++++++++++++++
Asrc/libfrosthigh/verify_sig_share.c | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrostlow/Makefile.am | 12++++++++++++
Asrc/libfrostlow/frost_low.c | 379+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrosttrusteddealer/Makefile.am | 13+++++++++++++
Asrc/libfrosttrusteddealer/trusteddealer.c | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/libfrostverify/Makefile.am | 14++++++++++++++
Asrc/libfrostverify/verify_signature.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/restclient/Makefile.am | 30++++++++++++++++++++++++++++++
Asrc/restclient/frosix_api_auth-challenge_request.c | 286+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/restclient/frosix_api_config.c | 280+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/restclient/frosix_api_curl_defaults.c | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/restclient/frosix_api_curl_defaults.h | 38++++++++++++++++++++++++++++++++++++++
Asrc/restclient/frosix_api_dkg-commitment_request.c | 387+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/restclient/frosix_api_dkg-key_delete.c | 258+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/restclient/frosix_api_dkg-key_store.c | 377+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/restclient/frosix_api_dkg-share_request.c | 444+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/restclient/frosix_api_seed_get.c | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/restclient/frosix_api_sig-commitment_request.c | 364+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/restclient/frosix_api_sig-share_request.c | 354+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/restclient/test_frosix.c | 237+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/Makefile.am | 41+++++++++++++++++++++++++++++++++++++++++
Asrc/util/frosix-config.c | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/frosix-config.in | 12++++++++++++
Asrc/util/frosix-util.c | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/frosix_crypto.c | 289++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/os_installation.c | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/pin.c | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
323 files changed, 44315 insertions(+), 0 deletions(-)

diff --git a/AUTHORS b/AUTHORS @@ -0,0 +1,2 @@ +Joel Urech <joeltobias.urech@students.bfh.ch> +Christian Grothoff <grothoff@taler.net> +\ No newline at end of file diff --git a/COPYING b/COPYING @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +<http://www.gnu.org/licenses/>. diff --git a/ChangeLog b/ChangeLog diff --git a/INSTALL b/INSTALL @@ -0,0 +1,368 @@ +Installation Instructions +************************* + + Copyright (C) 1994-1996, 1999-2002, 2004-2017, 2020-2021 Free +Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell command './configure && make && make install' +should configure, build, and install this package. The following +more-detailed instructions are generic; see the 'README' file for +instructions specific to this package. Some packages provide this +'INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The 'configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a 'Makefile' in each directory of the package. +It may also create one or more '.h' files containing system-dependent +definitions. Finally, it creates a shell script 'config.status' that +you can run in the future to recreate the current configuration, and a +file 'config.log' containing compiler output (useful mainly for +debugging 'configure'). + + It can also use an optional file (typically called 'config.cache' and +enabled with '--cache-file=config.cache' or simply '-C') that saves the +results of its tests to speed up reconfiguring. Caching is disabled by +default to prevent problems with accidental use of stale cache files. + + If you need to do unusual things to compile the package, please try +to figure out how 'configure' could check whether to do them, and mail +diffs or instructions to the address given in the 'README' so they can +be considered for the next release. If you are using the cache, and at +some point 'config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file 'configure.ac' (or 'configure.in') is used to create +'configure' by a program called 'autoconf'. You need 'configure.ac' if +you want to change it or regenerate 'configure' using a newer version of +'autoconf'. + + The simplest way to compile this package is: + + 1. 'cd' to the directory containing the package's source code and type + './configure' to configure the package for your system. + + Running 'configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type 'make' to compile the package. + + 3. Optionally, type 'make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type 'make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the 'make install' phase executed with root + privileges. + + 5. Optionally, type 'make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior 'make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing 'make clean'. To also remove the + files that 'configure' created (so you can compile the package for + a different kind of computer), type 'make distclean'. There is + also a 'make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type 'make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide 'make + distcheck', which can by used by developers to test that all other + targets like 'make install' and 'make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the 'configure' script does not know about. Run './configure --help' +for details on some of the pertinent environment variables. + + You can give 'configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here is +an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU 'make'. 'cd' to the +directory where you want the object files and executables to go and run +the 'configure' script. 'configure' automatically checks for the source +code in the directory that 'configure' is in and in '..'. This is known +as a "VPATH" build. + + With a non-GNU 'make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use 'make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple '-arch' options to the +compiler but only a single '-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the 'lipo' tool if you have problems. + +Installation Names +================== + + By default, 'make install' installs the package's commands under +'/usr/local/bin', include files under '/usr/local/include', etc. You +can specify an installation prefix other than '/usr/local' by giving +'configure' the option '--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option '--exec-prefix=PREFIX' to 'configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like '--bindir=DIR' to specify different values for particular +kinds of files. Run 'configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the default +for these options is expressed in terms of '${prefix}', so that +specifying just '--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to 'configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +'make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, 'make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +'${prefix}'. Any directories that were specified during 'configure', +but not in terms of '${prefix}', must each be overridden at install time +for the entire installation to be relocated. The approach of makefile +variable overrides for each directory variable is required by the GNU +Coding Standards, and ideally causes no recompilation. However, some +platforms have known limitations with the semantics of shared libraries +that end up requiring recompilation when using this method, particularly +noticeable in packages that use GNU Libtool. + + The second method involves providing the 'DESTDIR' variable. For +example, 'make install DESTDIR=/alternate/directory' will prepend +'/alternate/directory' before all installation names. The approach of +'DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of '${prefix}' +at 'configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving 'configure' the +option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'. + + Some packages pay attention to '--enable-FEATURE' options to +'configure', where FEATURE indicates an optional part of the package. +They may also pay attention to '--with-PACKAGE' options, where PACKAGE +is something like 'gnu-as' or 'x' (for the X Window System). The +'README' should mention any '--enable-' and '--with-' options that the +package recognizes. + + For packages that use the X Window System, 'configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the 'configure' options '--x-includes=DIR' and +'--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of 'make' will be. For these packages, running './configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with 'make V=1'; while running './configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with 'make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC +is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX 'make' updates targets which have the same timestamps as their +prerequisites, which makes it generally unusable when shipped generated +files such as 'configure' are involved. Use GNU 'make' instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its '<wchar.h>' header file. The option '-nodtk' can be used as a +workaround. If GNU CC is not installed, it is therefore recommended to +try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put '/usr/ucb' early in your 'PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in '/usr/bin'. So, if you need '/usr/ucb' +in your 'PATH', put it _after_ '/usr/bin'. + + On Haiku, software installed for all users goes in '/boot/common', +not '/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features 'configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, 'configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +'--build=TYPE' option. TYPE can either be a short name for the system +type, such as 'sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file 'config.sub' for the possible values of each field. If +'config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option '--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with '--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for 'configure' scripts to share, +you can create a site shell script called 'config.site' that gives +default values for variables like 'CC', 'cache_file', and 'prefix'. +'configure' looks for 'PREFIX/share/config.site' if it exists, then +'PREFIX/etc/config.site' if it exists. Or, you can set the +'CONFIG_SITE' environment variable to the location of the site script. +A warning: not all 'configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to 'configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the 'configure' command line, using 'VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified 'gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an +Autoconf limitation. Until the limitation is lifted, you can use this +workaround: + + CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash + +'configure' Invocation +====================== + + 'configure' recognizes the following options to control how it +operates. + +'--help' +'-h' + Print a summary of all of the options to 'configure', and exit. + +'--help=short' +'--help=recursive' + Print a summary of the options unique to this package's + 'configure', and exit. The 'short' variant lists options used only + in the top level, while the 'recursive' variant lists options also + present in any nested packages. + +'--version' +'-V' + Print the version of Autoconf used to generate the 'configure' + script, and exit. + +'--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally 'config.cache'. FILE defaults to '/dev/null' to + disable caching. + +'--config-cache' +'-C' + Alias for '--cache-file=config.cache'. + +'--quiet' +'--silent' +'-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to '/dev/null' (any error + messages will still be shown). + +'--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + 'configure' can determine that directory automatically. + +'--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: for + more details, including other options available for fine-tuning the + installation locations. + +'--no-create' +'-n' + Run the configure checks, but stop before creating any output + files. + +'configure' also accepts some other, not widely useful, options. Run +'configure --help' for more details. diff --git a/Makefile.am b/Makefile.am @@ -0,0 +1,5 @@ +# This Makefile is in the public domain + +SUBDIRS = . contrib src + +ACLOCAL_AMFLAGS = -I m4 +\ No newline at end of file diff --git a/NEWS b/NEWS diff --git a/README b/README @@ -0,0 +1,77 @@ +====== +FROSIX +====== + +This package includes the Frosix core logic. The code is released +under the GNU Affero General Public License (v3 or later). See +COPYING for details. + + +Description +=========== + +At this early stage, Frosix is an implementation of the FROST +threshold signature scheme published at the end of 2020 by Chelsea +Komlo and Ian Goldberg (see https://eprint.iacr.org/2020/852.pdf). +Therefore Frosix is rather just the library libfrost at the moment. + +Frosix aims to provide a safe and secure EdDSA compatible threshold +signature service, based on the previously mentioned FROST protocol. +In the end, Frosix should include an implementation to run small web +servers - the providers - which a software, running on a client, can +access via a simple REST API. The software on the client side will be +a simple CLI as a first step. + +The providers are designed to only store the data necessary for its +service, either encrypted without knowing the key, or just in form of +a salted hash. The drawback of this complete zero knowledge driven +strategy is that the information which is needed to let a provider +participate in a signing process, has again to be stored securly by +the user. Obviously this means that the attacking vector of such a +provider is really small. But what happens if the secret data is +stolen? + +For this reason there will be a further security mechanism in Frosix. +Just as with GNU Anastasis (see +https://git.taler.net/anastasis.git/tree/doc/sphinx/rest.rst), Frosix +providers are required to challenge, respectively authenticate their +users. This ensures that, depending on the challenge selected, only +the legitimate user can have a valid signature generated. + + +Dependencies +============ + +libsodium : ISC License +libgnunet : GPLv3+ + + +Directory structure +=================== + +src/include/ + -- installed headers for public APIs + +src/libfrostdistkeygen/ + -- contains the logic to perform a distributed key generation process + +src/libfrosthigh/ + -- contains the main logic to compute a signature share + +src/libfrostlow/ + -- wrapper for the crypto function of libsodium + +src/libfrosttrusteddealer/ + -- contains a function to generate a key pair, for testing purposes only + +src/libfrostverify/ + -- contains a function to verify a given signature over a specific message + +src/testing + -- contains an integration test + +contrib/ + -- contains resource files + +doc/ + -- contains the documentation files of this project +\ No newline at end of file diff --git a/bootstrap b/bootstrap @@ -0,0 +1,35 @@ +#!/bin/sh + +if ! git --version >/dev/null; then + echo "git not installed" + exit 1 +fi + +#echo "$0: Updating submodules" +#echo | git submodule update --init + +#git submodule update --init + +#./contrib/gana-update.sh + +# This is more portable than `which' but comes with +# the caveat of not(?) properly working on busybox's ash: +existence() +{ + command -v "$1" >/dev/null 2>&1 +} + + +if existence uncrustify; then + echo "Installing uncrustify hook and configuration" + # Install uncrustify format symlink (if possible) + ln -s contrib/uncrustify.cfg uncrustify.cfg 2> /dev/null + # Install pre-commit hook (if possible) + ln -s ../../contrib/uncrustify_precommit .git/hooks/pre-commit 2> /dev/null +else + echo "Uncrustify not detected, hook not installed. Please install uncrustify if you plan on doing development" +fi + + +echo "$0: Running autoreconf" +autoreconf -if diff --git a/configure.ac b/configure.ac @@ -0,0 +1,93 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.69]) +AC_INIT([frosix], [0.0.1], [joeltobias.urech@students.bfh.ch]) +AC_CONFIG_HEADERS([frosix_config.h]) + +# Checks for programs. +AM_INIT_AUTOMAKE([subdir-objects 1.9 tar-pax]) +# pretty build rules +AM_SILENT_RULES([yes]) + +AC_CONFIG_MACRO_DIR([m4]) + +AC_PROG_AWK +AC_PROG_CC +AC_PROG_OBJC +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AM_PROG_CC_C_O + +LT_INIT([disable-static dlopen]) + +CFLAGS="-Wall $CFLAGS" + +# Checks for libraries. + +# check for libsodium version >= 1.0.18 - from gnunet +libsodium=0 +AC_CHECK_HEADER([sodium.h], + [AC_CHECK_LIB([sodium], [crypto_core_ed25519_scalar_mul], + [libsodium=1], + [libsodium=0])]) + +AS_IF([test "x$libsodium" = "x0"], + [AC_MSG_ERROR([GNUnet requires libsodium >= 1.0.18])]) + +# Check for GNUnet's libgnunetutil. - from anastasis +libgnunetutil=0 +AC_MSG_CHECKING([for libgnunetutil]) +AC_ARG_WITH(gnunet, + [AS_HELP_STRING([--with-gnunet=PFX], [base of GNUnet installation])], + [AC_MSG_RESULT([given as $with_gnunet])], + [AC_MSG_RESULT(not given) + with_gnunet=yes]) +AS_CASE([$with_gnunet], + [yes], [], + [no], [AC_MSG_ERROR([--with-gnunet is required])], + [LDFLAGS="-L$with_gnunet/lib $LDFLAGS" + CPPFLAGS="-I$with_gnunet/include $CPPFLAGS"]) +AC_CHECK_HEADERS([gnunet/gnunet_util_lib.h], + [AC_CHECK_LIB([gnunetutil], + [GNUNET_SCHEDULER_run], + [libgnunetutil=1])]) +AS_IF([test $libgnunetutil != 1], + [AC_MSG_ERROR([[ +*** +*** You need libgnunetutil to build this program. +*** This library is part of GNUnet, available at +*** https://gnunet.org +*** ]])]) + +# Checks for header files. +AC_CHECK_HEADERS([string.h stdio.h time.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_SIZE_T +AC_TYPE_UINT32_T +AC_TYPE_UINT8_T + +# Checks for library functions. +AC_CHECK_FUNCS([memset]) + +AC_CONFIG_FILES([Makefile + contrib/Makefile + doc/Makefile + doc/doxygen/Makefile + src/Makefile + src/authorization/Makefile + src/backend/Makefile + src/cli/Makefile + src/frosixdb/Makefile + src/include/Makefile + src/libfrostdistkeygen/Makefile + src/libfrosthigh/Makefile + src/libfrostlow/Makefile + src/libfrosttrusteddealer/Makefile + src/libfrostverify/Makefile + src/libfrosix/Makefile + src/restclient/Makefile + src/util/Makefile]) +AC_OUTPUT diff --git a/contrib/Makefile.am b/contrib/Makefile.am @@ -0,0 +1,63 @@ +# This Makefile.am is in the public domain +# Process this file with automake to produce Makefile.in + +SUBDIRS = . + +# English (en) +tosendir=$(datadir)/frosix/tos/en + +# English (en) +ppendir=$(datadir)/frosix/pp/en + +tosen_DATA = \ + tos/en/0.txt \ + tos/en/0.pdf \ + tos/en/0.epub \ + tos/en/0.xml \ + tos/en/0.html + +ppen_DATA = \ + pp/en/0.txt \ + pp/en/0.pdf \ + pp/en/0.epub \ + pp/en/0.xml \ + pp/en/0.html + +pkgdatadir= $(prefix)/share/frosix/ + +EXTRA_DIST = \ + $(pkgdata_DATA) \ + $(tosen_DATA) \ + $(ppen_DATA) \ + tos/Makefile \ + tos/README \ + tos/tos.rst \ + tos/conf.py \ + tos/locale/de/LC_MESSAGES/tos.po \ + pp/Makefile \ + pp/README \ + pp/pp.rst \ + pp/conf.py \ + pp/locale/de/LC_MESSAGES/pp.po \ + uncrustify.cfg \ + uncrustify_precommit \ + microhttpd.tag + +pkgdata_DATA = \ + provider-list.json + +# Change the set of supported languages here. You should +# also update tos'XX'data and EXTRA_DIST accordingly. +TOS_LANGUAGES="en de" +PP_LANGUAGES="en de" + +# Change the terms-of-service version (Etag) to generate here! +# This value should be incremented whenever there is a substantive +# change in the original text (but not for the translations). +TOS_VERSION=0 +PP_VERSION=0 + +update-tos: + VERSION=$(TOS_VERSION) ./update-tos.sh $(TOS_LANGUAGES) +update-pp: + VERSION=$(PP_VERSION) ./update-pp.sh $(PP_LANGUAGES) diff --git a/contrib/microhttpd.tag b/contrib/microhttpd.tag @@ -0,0 +1,182 @@ +<?xml version='1.0' encoding='UTF-8' standalone='yes' ?> +<tagfile> + <compound kind="file"> + <name>microhttpd_lib.h</name> + <path></path> + <filename>microhttpd.h</filename> + <member kind="define"> + <type>#define</type> + <name>MHD_YES</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_NO</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_OK</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_BAD_REQUEST</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_URI_TOO_LONG</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_PAYLOAD_TOO_LARGE</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_REQUEST_TIMEOUT</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_ACCEPTED</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_NOT_FOUND</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_NO_CONTENT</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_GONE</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_PRECONDITION_FAILED</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_CONFLICT</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_FORBIDDEN</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_SERVICE_UNAVAILABLE</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_FAILED_DEPENDENCY</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_INTERNAL_SERVER_ERROR</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_OPTION_NOTIFY_COMPLETED</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_BAD_GATEWAY</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_GATEWAY_TIMEOUT</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_METHOD_NOT_ALLOWED</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_UNAUTHORIZED</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_PAYMENT_REQUIRED</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_NOT_IMPLEMENTED</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_NOT_ACCEPTABLE</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_ALREADY_REPORTED</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_EXPECTATION_FAILED</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="define"> + <type>#define</type> + <name>MHD_HTTP_TOO_MANY_REQUESTS</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist></arglist> + </member> + <member kind="typedef"> + <type>int</type> + <name>MHD_AccessHandlerCallback</name> + <anchorfile>microhttpd.h</anchorfile> + <arglist>)(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls)</arglist> + </member> + </compound> +</tagfile> diff --git a/contrib/pp/README b/contrib/pp/README @@ -0,0 +1,58 @@ +This directory contains the privacy policy (template) for Anastasis +operators. + + +Dependencies +============ + +Generating a new Privacy Policy requires Sphinx, LaTeX with babel +packages for all supported languages. On Debian, you should +at least install: + +$ apt install python3-sphinx sphinx-intl texlive-lang-german texlive-lang-english + +(NOTE: List may be incomplete.) + + +Updating the Privacy Policy +=========================== + +The master file with the Privacy Policy is 'pp.rst'. + +If you make substantial changes, you MUST change the "PP_VERSION" +in contrib/Makefile.am to the new Etag. + +To begin the translation into other languages after editing the master +file, run + +$ make gettext + +to generate the master PO file. Then, run + +$ sphinx-intl update -p _build/locale/ -l de -l fr -l it + +to update the PO files for the various languages (extend the list of +languages as necessary). The PO files for the translators are kept +at locale/$LANG/LC_MESSAGES/pp.po for the language $LANG. + +Once all PO files have been updated with new translations, run + +$ make update-pp + +in the "contrib/" directory to generate all of the formats. The +respective make rule calls the '../update-pp.sh' script in the +contrib/ directory, which calls the 'Makefile' in the pp/ +directory for the various supported languages and file formats +and then moves the generated files to the target directory +('contrib/pp/$LANG/$VERSION.$FORMAT') + + +Adding a new language +===================== + +To add a new language $LANG, add $LANG to "PP_LANGUAGES" in +'contrib/Makefile.am' and run + +$ sphinx-intl update -p _build/gettext -l $LANG + +to generate the PO template. diff --git a/contrib/pp/conf.py b/contrib/pp/conf.py @@ -0,0 +1,282 @@ +""" + This file is part of GNU TALER. + Copyright (C) 2014-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + + @author Florian Dold + @author Benedikt Muller + @author Sree Harsha Totakura + @author Marcello Stanisci +""" +# -*- coding: utf-8 -*- +# +# neuro documentation build configuration file, created by +# sphinx-quickstart on Sat May 31 13:11:06 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +sys.path.append(os.path.abspath('_exts')) + +#import taler_sphinx_theme + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = '1.8.5' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.todo', + 'sphinx.ext.imgmath', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +source_suffix = { + '.rst': 'restructuredtext', +} + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'pp' + +# General information about the project. +project = u'pp' +copyright = u'2014-2020 Taler Systems SA (GPLv3+ or GFDL 1.3+)' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0' +# The full version, including alpha/beta/rc tags. +release = '0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# language = "en de" + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build', '_exts', 'cf', 'prebuilt'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# default_role = "ts:type" + +locale_dirs = ['locale/'] +gettext_compact = False + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'epub' + +#html_theme_path = taler_sphinx_theme.html_theme_path() + +#html_sidebars = {'**': ['logo-text.html', 'globaltoc.html', 'searchbox.html']} + +rst_epilog = "" + +html_show_sphinx = False + +html_theme_options = { + # Set the name of the project to appear in the sidebar + "relbar1": "false", + "footer": "false", +} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +html_title = "Taler Terms of Service" + +# A shorter title for the navigation bar. Default is the same as html_title. +html_short_title = "Terms of Service" + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +# html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + #'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('pp', 'pp.tex', + 'Privacy Policy', 'GNU Taler team', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# latex_appendices = ["fdl-1.3"] + +# If false, no module index is generated. +#latex_domain_indices = True + +# -- Options for manual page output --------------------------------------- + +# If true, show URL addresses after external links. +#man_show_urls = False + +# -- Options for Texinfo output ------------------------------------------- + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# -- Options for epub output ---------------------------- + +epub_basename = "pp" + +epub_title = "Terms of Service" diff --git a/contrib/pp/en/0.epub b/contrib/pp/en/0.epub Binary files differ. diff --git a/contrib/pp/en/0.html b/contrib/pp/en/0.html @@ -0,0 +1,188 @@ + + +<html lang="en"> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Privacy Policy &#8212; Taler Privacy Policy</title> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="_static/epub.css" type="text/css" /> + <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script> + <script src="_static/jquery.js"></script> + <script src="_static/underscore.js"></script> + <script src="_static/doctools.js"></script> + </head><body> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body" role="main"> + + <div class="section" id="privacy-policy"> +<h1>Privacy Policy<a class="headerlink" href="#privacy-policy" title="Permalink to this headline">¶</a></h1> +<p>Last Updated: 07.09.2021</p> +<p>This Privacy Policy describes the policies and procedures of Anastasis +SARL (“we,” “our,” or “us”) pertaining to the collection, use, and +disclosure of your information on our sites and related mobile +applications and products we offer (the “Services”). This Privacy +Statement applies to your personal data when you use our Services, and +does not apply to online websites or services that we do not own or +control.</p> +<div class="section" id="overview"> +<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2> +<p>Your privacy is important to us. We follow a few fundamental +principles: We don’t ask you for personally identifiable information +(defined below). That being said, your contact information, such as +your phone number, social media handle, or email address (depending on +how you contact us), may be collected when you communicate with us, +for example to report a bug or other error related to Anastasis. We +don’t share your information with third parties except when strictly +required to deliver you our Services and products, or to comply with +the law. If you have any questions or concerns about this policy, +please reach out to us at <a class="reference external" href="mailto:privacy&#37;&#52;&#48;anastasis&#46;lu">privacy<span>&#64;</span>anastasis<span>&#46;</span>lu</a>.</p> +</div> +<div class="section" id="how-you-accept-this-policy"> +<h2>How you accept this policy<a class="headerlink" href="#how-you-accept-this-policy" title="Permalink to this headline">¶</a></h2> +<p>By using our Services or visiting our sites, you agree to the use, disclosure, +and procedures outlined in this Privacy Policy.</p> +</div> +<div class="section" id="what-personal-information-do-we-collect-from-our-users"> +<h2>What personal information do we collect from our users?<a class="headerlink" href="#what-personal-information-do-we-collect-from-our-users" title="Permalink to this headline">¶</a></h2> +<p>The information we collect from you falls into two categories: (i) personally +identifiable information (i.e., data that could potentially identify you as an +individual) (“Personal Information”), and (ii) non-personally identifiable +information (i.e., information that cannot be used to identify who you are) +(“Non-Personal Information”). This Privacy Policy covers both categories and +will tell you how we might collect and use each type.</p> +<p>We do our best to not collect any Personal Information from Anastasis +users. The detailed Personal Information Anastasis asks from you during +the regular backup and recovery process at the beginning is never shared +with us and only used to create a cryptographic account identifier which +does not allow us to recover any of your details.</p> +<p>That being said, when using our Services to recover key material, we may +inherently receive the following information (depending on your choice of +authentication method):</p> +<blockquote> +<div><ul class="simple"> +<li><p>Bank account details necessary when receiving funds from you to authenticate via a SEPA transfer. We will store these as part of our business records for accounting, and our bank will also be legally obliged to store the details for many years.</p></li> +<li><p>Your phone number when using SMS authentication. We rely on third party providers (such as your mobile network operator) to deliver the SMS to you. These third parties will see the SMS message sent to you and could thus learn that you are using Anastasis. SMS is inherently insecure, and you should expect many governments and private parties to be able to observe these messages. However, we do not store your SMS number on our systems, except maybe in short-term logs to diagnose errors.</p></li> +<li><p>Your e-mail address when using E-mail authentication. We rely on the Internet and your E-mail provider to deliver the E-mail to you. Internet service providers will see the E-mail message sent to you and could thus learn that you are using Anastasis. E-mail is inherently insecure, and you should expect many governments and private parties to be able to observe these messages. However, we do not store your E-mail address on our systems, except maybe in short-term logs to diagnose errors.</p></li> +<li><p>Your physical address when using postal mail authentication. We rely on external providers for printing and sending the letter to you. These providers will need to learn your address and could learn that you are using Anastasis. Physical mail has strict privacy protections by law, but governments are known to break postal secrecy. We do not store your physical address on our systems, except maybe in short-term logs to diagnose errors.</p></li> +<li><p>When you contact us. We may collect certain information if you choose to contact us, for example to report a bug or other error with the Taler Wallet. This may include contact information such as your name, email address or phone number depending on the method you choose to contact us.</p></li> +</ul> +</div></blockquote> +</div> +<div class="section" id="how-we-collect-and-process-information"> +<h2>How we collect and process information<a class="headerlink" href="#how-we-collect-and-process-information" title="Permalink to this headline">¶</a></h2> +<p>We may process your information for the following reasons:</p> +<blockquote> +<div><ul class="simple"> +<li><p>to authenticate you during secret recovery</p></li> +<li><p>to support you using Anastasis when you contact us</p></li> +</ul> +</div></blockquote> +</div> +<div class="section" id="how-we-share-and-use-the-information-we-gather"> +<h2>How we share and use the information we gather<a class="headerlink" href="#how-we-share-and-use-the-information-we-gather" title="Permalink to this headline">¶</a></h2> +<p>We may share your authentication data with other providers that assist +us in performing the authentication. We will try to use providers that +to the best of our knowledge respect your privacy and have good +privacy practices. We reserve the right to change authentication +providers at any time to ensure availability of our services.</p> +<p>We primarily use the limited information we receive directly from you to +enhance Anastasis. Some ways we may use your Personal Information are +to: Contact you when necessary to respond to your comments, answer your +questions, or obtain additional information on issues related to bugs or +errors with the Anastasis application that you reported.</p> +</div> +<div class="section" id="agents-or-third-party-partners"> +<h2>Agents or third party partners<a class="headerlink" href="#agents-or-third-party-partners" title="Permalink to this headline">¶</a></h2> +<p>We may provide your Personal Information to our employees, contractors, +agents, service providers, and designees (“Agents”) to enable them to perform +certain services for us exclusively, including: improvement and maintenance of +our software and Services. By accepting this Privacy Policy, as outlined +above, you consent to any such transfer.</p> +</div> +<div class="section" id="protection-of-us-and-others"> +<h2>Protection of us and others<a class="headerlink" href="#protection-of-us-and-others" title="Permalink to this headline">¶</a></h2> +<p>We reserve the right to access, read, preserve, and disclose any information +that we reasonably believe is necessary to comply with the law or a court +order.</p> +</div> +<div class="section" id="what-personal-information-can-i-access-or-change"> +<h2>What personal information can I access or change?<a class="headerlink" href="#what-personal-information-can-i-access-or-change" title="Permalink to this headline">¶</a></h2> +<p>You can request access to the information we have collected from +you. You can do this by contacting us at <a class="reference external" href="mailto:privacy&#37;&#52;&#48;anastasis&#46;lu">privacy<span>&#64;</span>anastasis<span>&#46;</span>lu</a>. We will +make sure to provide you with a copy of the data we process about +you. To comply with your request, we may ask you to verify your +identity. We will fulfill your request by sending your copy +electronically. For any subsequent access request, we may charge you +with an administrative fee. If you believe that the information we +have collected is incorrect, you are welcome to contact us so we can +update it and keep your data accurate. Any data that is no longer +needed for purposes specified in the “How We Use the Information We +Gather” section will be deleted after ninety (90) days.</p> +</div> +<div class="section" id="data-retention"> +<h2>Data retention<a class="headerlink" href="#data-retention" title="Permalink to this headline">¶</a></h2> +<p>Information entered into our bug tracker will be retained indefinitely +and is typically made public. We will only use it to triage the +problem. Beyond that, we do not retain personally identifiable +information about our users for longer than one week.</p> +</div> +<div class="section" id="data-security"> +<h2>Data security<a class="headerlink" href="#data-security" title="Permalink to this headline">¶</a></h2> +<p>We are committed to making sure your information is protected. We employ +several physical and electronic safeguards to keep your information safe, +including encrypted user passwords, two factor verification and authentication +on passwords where possible, and securing connections with industry standard +transport layer security. You are also welcome to contact us using GnuPG +encrypted e-mail. Even with all these precautions, we cannot fully guarantee +against the access, disclosure, alteration, or deletion of data through +events, including but not limited to hardware or software failure or +unauthorized use. Any information that you provide to us is done so entirely +at your own risk.</p> +</div> +<div class="section" id="changes-and-updates-to-privacy-policy"> +<h2>Changes and updates to privacy policy<a class="headerlink" href="#changes-and-updates-to-privacy-policy" title="Permalink to this headline">¶</a></h2> +<p>We reserve the right to update and revise this privacy policy at any time. We +occasionally review this Privacy Policy to make sure it complies with +applicable laws and conforms to changes in our business. We may need to update +this Privacy Policy, and we reserve the right to do so at any time. If we do +revise this Privacy Policy, we will update the “Effective Date” at the top +of this page so that you can tell if it has changed since your last visit. As +we generally do not collect contact information and also do not track your +visits, we will not be able to notify you directly. However, Anastasis clients +may inform you about a change in the privacy policy once they detect that the +policy has changed. Please review this Privacy Policy regularly to ensure that +you are aware of its terms. Any use of our Services after an amendment to our +Privacy Policy constitutes your acceptance to the revised or amended +agreement.</p> +</div> +<div class="section" id="international-users-and-visitors"> +<h2>International users and visitors<a class="headerlink" href="#international-users-and-visitors" title="Permalink to this headline">¶</a></h2> +<p>Our Services are (currently) hosted in Germany. If you are a user +accessing the Services from the Switzerland, Asia, US, or any other +region with laws or regulations governing personal data collection, +use, and disclosure that differ from the laws of Germany, please be +advised that through your continued use of the Services, which is +governed by the law of the country hosting the service, you are +transferring your Personal Information to Germany and you consent to +that transfer.</p> +</div> +<div class="section" id="questions"> +<h2>Questions<a class="headerlink" href="#questions" title="Permalink to this headline">¶</a></h2> +<p>Please contact us at <a class="reference external" href="mailto:privacy&#37;&#52;&#48;anastasis&#46;lu">privacy<span>&#64;</span>anastasis<span>&#46;</span>lu</a> if you have questions about our +privacy practices that are not addressed in this Privacy Statement.</p> +</div> +</div> + + + <div class="clearer"></div> + </div> + </div> + </div> + <div class="clearer"></div> + </div> + </body> +</html> +\ No newline at end of file diff --git a/contrib/pp/en/0.pdf b/contrib/pp/en/0.pdf Binary files differ. diff --git a/contrib/pp/en/0.txt b/contrib/pp/en/0.txt @@ -0,0 +1,219 @@ +Privacy Policy +************** + +Last Updated: 07.09.2021 + +This Privacy Policy describes the policies and procedures of Anastasis +SARL (“we,” “our,” or “us”) pertaining to the collection, use, and +disclosure of your information on our sites and related mobile +applications and products we offer (the “Services”). This Privacy +Statement applies to your personal data when you use our Services, and +does not apply to online websites or services that we do not own or +control. + + +Overview +======== + +Your privacy is important to us. We follow a few fundamental +principles: We don’t ask you for personally identifiable information +(defined below). That being said, your contact information, such as +your phone number, social media handle, or email address (depending on +how you contact us), may be collected when you communicate with us, +for example to report a bug or other error related to Anastasis. We +don’t share your information with third parties except when strictly +required to deliver you our Services and products, or to comply with +the law. If you have any questions or concerns about this policy, +please reach out to us at privacy@anastasis.lu. + + +How you accept this policy +========================== + +By using our Services or visiting our sites, you agree to the use, +disclosure, and procedures outlined in this Privacy Policy. + + +What personal information do we collect from our users? +======================================================= + +The information we collect from you falls into two categories: (i) +personally identifiable information (i.e., data that could potentially +identify you as an individual) (“Personal Information”), and (ii) non- +personally identifiable information (i.e., information that cannot be +used to identify who you are) (“Non-Personal Information”). This +Privacy Policy covers both categories and will tell you how we might +collect and use each type. + +We do our best to not collect any Personal Information from Anastasis +users. The detailed Personal Information Anastasis asks from you +during the regular backup and recovery process at the beginning is +never shared with us and only used to create a cryptographic account +identifier which does not allow us to recover any of your details. + +That being said, when using our Services to recover key material, we +may inherently receive the following information (depending on your +choice of authentication method): + + * Bank account details necessary when receiving funds from you to + authenticate via a SEPA transfer. We will store these as part of + our business records for accounting, and our bank will also be + legally obliged to store the details for many years. + + * Your phone number when using SMS authentication. We rely on third + party providers (such as your mobile network operator) to deliver + the SMS to you. These third parties will see the SMS message sent + to you and could thus learn that you are using Anastasis. SMS is + inherently insecure, and you should expect many governments and + private parties to be able to observe these messages. However, + we do not store your SMS number on our systems, except maybe in + short-term logs to diagnose errors. + + * Your e-mail address when using E-mail authentication. We rely on + the Internet and your E-mail provider to deliver the E-mail to + you. Internet service providers will see the E-mail message sent + to you and could thus learn that you are using Anastasis. E-mail + is inherently insecure, and you should expect many governments + and private parties to be able to observe these messages. + However, we do not store your E-mail address on our systems, + except maybe in short-term logs to diagnose errors. + + * Your physical address when using postal mail authentication. We + rely on external providers for printing and sending the letter to + you. These providers will need to learn your address and could + learn that you are using Anastasis. Physical mail has strict + privacy protections by law, but governments are known to break + postal secrecy. We do not store your physical address on our + systems, except maybe in short-term logs to diagnose errors. + + * When you contact us. We may collect certain information if you + choose to contact us, for example to report a bug or other error + with the Taler Wallet. This may include contact information such + as your name, email address or phone number depending on the + method you choose to contact us. + + +How we collect and process information +====================================== + +We may process your information for the following reasons: + + * to authenticate you during secret recovery + + * to support you using Anastasis when you contact us + + +How we share and use the information we gather +============================================== + +We may share your authentication data with other providers that assist +us in performing the authentication. We will try to use providers that +to the best of our knowledge respect your privacy and have good +privacy practices. We reserve the right to change authentication +providers at any time to ensure availability of our services. + +We primarily use the limited information we receive directly from you +to enhance Anastasis. Some ways we may use your Personal Information +are to: Contact you when necessary to respond to your comments, answer +your questions, or obtain additional information on issues related to +bugs or errors with the Anastasis application that you reported. + + +Agents or third party partners +============================== + +We may provide your Personal Information to our employees, +contractors, agents, service providers, and designees (“Agents”) to +enable them to perform certain services for us exclusively, including: +improvement and maintenance of our software and Services. By accepting +this Privacy Policy, as outlined above, you consent to any such +transfer. + + +Protection of us and others +=========================== + +We reserve the right to access, read, preserve, and disclose any +information that we reasonably believe is necessary to comply with the +law or a court order. + + +What personal information can I access or change? +================================================= + +You can request access to the information we have collected from you. +You can do this by contacting us at privacy@anastasis.lu. We will make +sure to provide you with a copy of the data we process about you. To +comply with your request, we may ask you to verify your identity. We +will fulfill your request by sending your copy electronically. For any +subsequent access request, we may charge you with an administrative +fee. If you believe that the information we have collected is +incorrect, you are welcome to contact us so we can update it and keep +your data accurate. Any data that is no longer needed for purposes +specified in the “How We Use the Information We Gather” section will +be deleted after ninety (90) days. + + +Data retention +============== + +Information entered into our bug tracker will be retained indefinitely +and is typically made public. We will only use it to triage the +problem. Beyond that, we do not retain personally identifiable +information about our users for longer than one week. + + +Data security +============= + +We are committed to making sure your information is protected. We +employ several physical and electronic safeguards to keep your +information safe, including encrypted user passwords, two factor +verification and authentication on passwords where possible, and +securing connections with industry standard transport layer security. +You are also welcome to contact us using GnuPG encrypted e-mail. Even +with all these precautions, we cannot fully guarantee against the +access, disclosure, alteration, or deletion of data through events, +including but not limited to hardware or software failure or +unauthorized use. Any information that you provide to us is done so +entirely at your own risk. + + +Changes and updates to privacy policy +===================================== + +We reserve the right to update and revise this privacy policy at any +time. We occasionally review this Privacy Policy to make sure it +complies with applicable laws and conforms to changes in our business. +We may need to update this Privacy Policy, and we reserve the right to +do so at any time. If we do revise this Privacy Policy, we will update +the “Effective Date” at the top of this page so that you can tell if +it has changed since your last visit. As we generally do not collect +contact information and also do not track your visits, we will not be +able to notify you directly. However, Anastasis clients may inform you +about a change in the privacy policy once they detect that the policy +has changed. Please review this Privacy Policy regularly to ensure +that you are aware of its terms. Any use of our Services after an +amendment to our Privacy Policy constitutes your acceptance to the +revised or amended agreement. + + +International users and visitors +================================ + +Our Services are (currently) hosted in Germany. If you are a user +accessing the Services from the Switzerland, Asia, US, or any other +region with laws or regulations governing personal data collection, +use, and disclosure that differ from the laws of Germany, please be +advised that through your continued use of the Services, which is +governed by the law of the country hosting the service, you are +transferring your Personal Information to Germany and you consent to +that transfer. + + +Questions +========= + +Please contact us at privacy@anastasis.lu if you have questions about +our privacy practices that are not addressed in this Privacy +Statement. diff --git a/contrib/pp/en/0.xml b/contrib/pp/en/0.xml @@ -0,0 +1,177 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE document PUBLIC "+//IDN docutils.sourceforge.net//DTD Docutils Generic//EN//XML" "http://docutils.sourceforge.net/docs/ref/docutils.dtd"> +<!-- Generated by Docutils 0.16 --> +<document source="/research/anastasis/anastasis/contrib/pp/pp.rst"> + <section ids="privacy-policy" names="privacy\ policy"> + <title>Privacy Policy</title> + <paragraph>Last Updated: 07.09.2021</paragraph> + <paragraph>This Privacy Policy describes the policies and procedures of Anastasis + SARL (“we,” “our,” or “us”) pertaining to the collection, use, and + disclosure of your information on our sites and related mobile + applications and products we offer (the “Services”). This Privacy + Statement applies to your personal data when you use our Services, and + does not apply to online websites or services that we do not own or + control.</paragraph> + <section ids="overview" names="overview"> + <title>Overview</title> + <paragraph>Your privacy is important to us. We follow a few fundamental + principles: We don’t ask you for personally identifiable information + (defined below). That being said, your contact information, such as + your phone number, social media handle, or email address (depending on + how you contact us), may be collected when you communicate with us, + for example to report a bug or other error related to Anastasis. We + don’t share your information with third parties except when strictly + required to deliver you our Services and products, or to comply with + the law. If you have any questions or concerns about this policy, + please reach out to us at <reference refuri="mailto:privacy@anastasis.lu">privacy@anastasis.lu</reference>.</paragraph> + </section> + <section ids="how-you-accept-this-policy" names="how\ you\ accept\ this\ policy"> + <title>How you accept this policy</title> + <paragraph>By using our Services or visiting our sites, you agree to the use, disclosure, + and procedures outlined in this Privacy Policy.</paragraph> + </section> + <section ids="what-personal-information-do-we-collect-from-our-users" names="what\ personal\ information\ do\ we\ collect\ from\ our\ users?"> + <title>What personal information do we collect from our users?</title> + <paragraph>The information we collect from you falls into two categories: (i) personally + identifiable information (i.e., data that could potentially identify you as an + individual) (“Personal Information”), and (ii) non-personally identifiable + information (i.e., information that cannot be used to identify who you are) + (“Non-Personal Information”). This Privacy Policy covers both categories and + will tell you how we might collect and use each type.</paragraph> + <paragraph>We do our best to not collect any Personal Information from Anastasis + users. The detailed Personal Information Anastasis asks from you during + the regular backup and recovery process at the beginning is never shared + with us and only used to create a cryptographic account identifier which + does not allow us to recover any of your details.</paragraph> + <paragraph>That being said, when using our Services to recover key material, we may + inherently receive the following information (depending on your choice of + authentication method):</paragraph> + <block_quote> + <bullet_list bullet="*"> + <list_item> + <paragraph>Bank account details necessary when receiving funds from you to authenticate via a SEPA transfer. We will store these as part of our business records for accounting, and our bank will also be legally obliged to store the details for many years.</paragraph> + </list_item> + <list_item> + <paragraph>Your phone number when using SMS authentication. We rely on third party providers (such as your mobile network operator) to deliver the SMS to you. These third parties will see the SMS message sent to you and could thus learn that you are using Anastasis. SMS is inherently insecure, and you should expect many governments and private parties to be able to observe these messages. However, we do not store your SMS number on our systems, except maybe in short-term logs to diagnose errors.</paragraph> + </list_item> + <list_item> + <paragraph>Your e-mail address when using E-mail authentication. We rely on the Internet and your E-mail provider to deliver the E-mail to you. Internet service providers will see the E-mail message sent to you and could thus learn that you are using Anastasis. E-mail is inherently insecure, and you should expect many governments and private parties to be able to observe these messages. However, we do not store your E-mail address on our systems, except maybe in short-term logs to diagnose errors.</paragraph> + </list_item> + <list_item> + <paragraph>Your physical address when using postal mail authentication. We rely on external providers for printing and sending the letter to you. These providers will need to learn your address and could learn that you are using Anastasis. Physical mail has strict privacy protections by law, but governments are known to break postal secrecy. We do not store your physical address on our systems, except maybe in short-term logs to diagnose errors.</paragraph> + </list_item> + <list_item> + <paragraph>When you contact us. We may collect certain information if you choose to contact us, for example to report a bug or other error with the Taler Wallet. This may include contact information such as your name, email address or phone number depending on the method you choose to contact us.</paragraph> + </list_item> + </bullet_list> + </block_quote> + </section> + <section ids="how-we-collect-and-process-information" names="how\ we\ collect\ and\ process\ information"> + <title>How we collect and process information</title> + <paragraph>We may process your information for the following reasons:</paragraph> + <block_quote> + <bullet_list bullet="*"> + <list_item> + <paragraph>to authenticate you during secret recovery</paragraph> + </list_item> + <list_item> + <paragraph>to support you using Anastasis when you contact us</paragraph> + </list_item> + </bullet_list> + </block_quote> + </section> + <section ids="how-we-share-and-use-the-information-we-gather" names="how\ we\ share\ and\ use\ the\ information\ we\ gather"> + <title>How we share and use the information we gather</title> + <paragraph>We may share your authentication data with other providers that assist + us in performing the authentication. We will try to use providers that + to the best of our knowledge respect your privacy and have good + privacy practices. We reserve the right to change authentication + providers at any time to ensure availability of our services.</paragraph> + <paragraph>We primarily use the limited information we receive directly from you to + enhance Anastasis. Some ways we may use your Personal Information are + to: Contact you when necessary to respond to your comments, answer your + questions, or obtain additional information on issues related to bugs or + errors with the Anastasis application that you reported.</paragraph> + </section> + <section ids="agents-or-third-party-partners" names="agents\ or\ third\ party\ partners"> + <title>Agents or third party partners</title> + <paragraph>We may provide your Personal Information to our employees, contractors, + agents, service providers, and designees (“Agents”) to enable them to perform + certain services for us exclusively, including: improvement and maintenance of + our software and Services. By accepting this Privacy Policy, as outlined + above, you consent to any such transfer.</paragraph> + </section> + <section ids="protection-of-us-and-others" names="protection\ of\ us\ and\ others"> + <title>Protection of us and others</title> + <paragraph>We reserve the right to access, read, preserve, and disclose any information + that we reasonably believe is necessary to comply with the law or a court + order.</paragraph> + </section> + <section ids="what-personal-information-can-i-access-or-change" names="what\ personal\ information\ can\ i\ access\ or\ change?"> + <title>What personal information can I access or change?</title> + <paragraph>You can request access to the information we have collected from + you. You can do this by contacting us at <reference refuri="mailto:privacy@anastasis.lu">privacy@anastasis.lu</reference>. We will + make sure to provide you with a copy of the data we process about + you. To comply with your request, we may ask you to verify your + identity. We will fulfill your request by sending your copy + electronically. For any subsequent access request, we may charge you + with an administrative fee. If you believe that the information we + have collected is incorrect, you are welcome to contact us so we can + update it and keep your data accurate. Any data that is no longer + needed for purposes specified in the “How We Use the Information We + Gather” section will be deleted after ninety (90) days.</paragraph> + </section> + <section ids="data-retention" names="data\ retention"> + <title>Data retention</title> + <paragraph>Information entered into our bug tracker will be retained indefinitely + and is typically made public. We will only use it to triage the + problem. Beyond that, we do not retain personally identifiable + information about our users for longer than one week.</paragraph> + </section> + <section ids="data-security" names="data\ security"> + <title>Data security</title> + <paragraph>We are committed to making sure your information is protected. We employ + several physical and electronic safeguards to keep your information safe, + including encrypted user passwords, two factor verification and authentication + on passwords where possible, and securing connections with industry standard + transport layer security. You are also welcome to contact us using GnuPG + encrypted e-mail. Even with all these precautions, we cannot fully guarantee + against the access, disclosure, alteration, or deletion of data through + events, including but not limited to hardware or software failure or + unauthorized use. Any information that you provide to us is done so entirely + at your own risk.</paragraph> + </section> + <section ids="changes-and-updates-to-privacy-policy" names="changes\ and\ updates\ to\ privacy\ policy"> + <title>Changes and updates to privacy policy</title> + <paragraph>We reserve the right to update and revise this privacy policy at any time. We + occasionally review this Privacy Policy to make sure it complies with + applicable laws and conforms to changes in our business. We may need to update + this Privacy Policy, and we reserve the right to do so at any time. If we do + revise this Privacy Policy, we will update the “Effective Date” at the top + of this page so that you can tell if it has changed since your last visit. As + we generally do not collect contact information and also do not track your + visits, we will not be able to notify you directly. However, Anastasis clients + may inform you about a change in the privacy policy once they detect that the + policy has changed. Please review this Privacy Policy regularly to ensure that + you are aware of its terms. Any use of our Services after an amendment to our + Privacy Policy constitutes your acceptance to the revised or amended + agreement.</paragraph> + </section> + <section ids="international-users-and-visitors" names="international\ users\ and\ visitors"> + <title>International users and visitors</title> + <paragraph>Our Services are (currently) hosted in Germany. If you are a user + accessing the Services from the Switzerland, Asia, US, or any other + region with laws or regulations governing personal data collection, + use, and disclosure that differ from the laws of Germany, please be + advised that through your continued use of the Services, which is + governed by the law of the country hosting the service, you are + transferring your Personal Information to Germany and you consent to + that transfer.</paragraph> + </section> + <section ids="questions" names="questions"> + <title>Questions</title> + <paragraph>Please contact us at <reference refuri="mailto:privacy@anastasis.lu">privacy@anastasis.lu</reference> if you have questions about our + privacy practices that are not addressed in this Privacy Statement.</paragraph> + </section> + </section> +</document> diff --git a/contrib/pp/locale/de/LC_MESSAGES/pp.po b/contrib/pp/locale/de/LC_MESSAGES/pp.po @@ -0,0 +1,511 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2014-2020 Taler Systems SA (GPLv3+ or GFDL 1.3+) +# This file is distributed under the same license as the pp package. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2020. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: pp 0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-09-07 21:42+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.9.1\n" + +#: ../../pp.rst:2 +msgid "Privacy Policy" +msgstr "" + +#: ../../pp.rst:4 +msgid "Last Updated: 07.09.2021" +msgstr "" + +#: ../../pp.rst:6 +msgid "" +"This Privacy Policy describes the policies and procedures of Anastasis " +"SARL (“we,” “our,” or “us”) pertaining to the collection, use, and " +"disclosure of your information on our sites and related mobile " +"applications and products we offer (the “Services”). This Privacy " +"Statement applies to your personal data when you use our Services, and " +"does not apply to online websites or services that we do not own or " +"control." +msgstr "" + +#: ../../pp.rst:16 +msgid "Overview" +msgstr "" + +#: ../../pp.rst:18 +msgid "" +"Your privacy is important to us. We follow a few fundamental principles: " +"We don’t ask you for personally identifiable information (defined below)." +" That being said, your contact information, such as your phone number, " +"social media handle, or email address (depending on how you contact us), " +"may be collected when you communicate with us, for example to report a " +"bug or other error related to Anastasis. We don’t share your information " +"with third parties except when strictly required to deliver you our " +"Services and products, or to comply with the law. If you have any " +"questions or concerns about this policy, please reach out to us at " +"privacy@anastasis.lu." +msgstr "" + +#: ../../pp.rst:31 +msgid "How you accept this policy" +msgstr "" + +#: ../../pp.rst:33 +msgid "" +"By using our Services or visiting our sites, you agree to the use, " +"disclosure, and procedures outlined in this Privacy Policy." +msgstr "" + +#: ../../pp.rst:38 +msgid "What personal information do we collect from our users?" +msgstr "" + +#: ../../pp.rst:40 +msgid "" +"The information we collect from you falls into two categories: (i) " +"personally identifiable information (i.e., data that could potentially " +"identify you as an individual) (“Personal Information”), and (ii) non-" +"personally identifiable information (i.e., information that cannot be " +"used to identify who you are) (“Non-Personal Information”). This Privacy " +"Policy covers both categories and will tell you how we might collect and " +"use each type." +msgstr "" + +#: ../../pp.rst:47 +msgid "" +"We do our best to not collect any Personal Information from Anastasis " +"users. The detailed Personal Information Anastasis asks from you during " +"the regular backup and recovery process at the beginning is never shared " +"with us and only used to create a cryptographic account identifier which " +"does not allow us to recover any of your details." +msgstr "" + +#: ../../pp.rst:53 +msgid "" +"That being said, when using our Services to recover key material, we may " +"inherently receive the following information (depending on your choice of" +" authentication method):" +msgstr "" + +#: ../../pp.rst:57 +msgid "" +"Bank account details necessary when receiving funds from you to " +"authenticate via a SEPA transfer. We will store these as part of our " +"business records for accounting, and our bank will also be legally " +"obliged to store the details for many years." +msgstr "" + +#: ../../pp.rst:59 +msgid "" +"Your phone number when using SMS authentication. We rely on third party " +"providers (such as your mobile network operator) to deliver the SMS to " +"you. These third parties will see the SMS message sent to you and could " +"thus learn that you are using Anastasis. SMS is inherently insecure, and " +"you should expect many governments and private parties to be able to " +"observe these messages. However, we do not store your SMS number on our " +"systems, except maybe in short-term logs to diagnose errors." +msgstr "" + +#: ../../pp.rst:61 +msgid "" +"Your e-mail address when using E-mail authentication. We rely on the " +"Internet and your E-mail provider to deliver the E-mail to you. Internet " +"service providers will see the E-mail message sent to you and could thus " +"learn that you are using Anastasis. E-mail is inherently insecure, and " +"you should expect many governments and private parties to be able to " +"observe these messages. However, we do not store your E-mail address on " +"our systems, except maybe in short-term logs to diagnose errors." +msgstr "" + +#: ../../pp.rst:63 +msgid "" +"Your physical address when using postal mail authentication. We rely on " +"external providers for printing and sending the letter to you. These " +"providers will need to learn your address and could learn that you are " +"using Anastasis. Physical mail has strict privacy protections by law, but" +" governments are known to break postal secrecy. We do not store your " +"physical address on our systems, except maybe in short-term logs to " +"diagnose errors." +msgstr "" + +#: ../../pp.rst:65 +msgid "" +"When you contact us. We may collect certain information if you choose to " +"contact us, for example to report a bug or other error with the Taler " +"Wallet. This may include contact information such as your name, email " +"address or phone number depending on the method you choose to contact us." +msgstr "" + +#: ../../pp.rst:69 +msgid "How we collect and process information" +msgstr "" + +#: ../../pp.rst:71 +msgid "We may process your information for the following reasons:" +msgstr "" + +#: ../../pp.rst:73 +msgid "to authenticate you during secret recovery" +msgstr "" + +#: ../../pp.rst:74 +msgid "to support you using Anastasis when you contact us" +msgstr "" + +#: ../../pp.rst:78 +msgid "How we share and use the information we gather" +msgstr "" + +#: ../../pp.rst:80 +msgid "" +"We may share your authentication data with other providers that assist us" +" in performing the authentication. We will try to use providers that to " +"the best of our knowledge respect your privacy and have good privacy " +"practices. We reserve the right to change authentication providers at " +"any time to ensure availability of our services." +msgstr "" + +#: ../../pp.rst:86 +msgid "" +"We primarily use the limited information we receive directly from you to " +"enhance Anastasis. Some ways we may use your Personal Information are to:" +" Contact you when necessary to respond to your comments, answer your " +"questions, or obtain additional information on issues related to bugs or " +"errors with the Anastasis application that you reported." +msgstr "" + +#: ../../pp.rst:94 +msgid "Agents or third party partners" +msgstr "" + +#: ../../pp.rst:96 +msgid "" +"We may provide your Personal Information to our employees, contractors, " +"agents, service providers, and designees (“Agents”) to enable them to " +"perform certain services for us exclusively, including: improvement and " +"maintenance of our software and Services. By accepting this Privacy " +"Policy, as outlined above, you consent to any such transfer." +msgstr "" + +#: ../../pp.rst:104 +msgid "Protection of us and others" +msgstr "" + +#: ../../pp.rst:106 +msgid "" +"We reserve the right to access, read, preserve, and disclose any " +"information that we reasonably believe is necessary to comply with the " +"law or a court order." +msgstr "" + +#: ../../pp.rst:112 +msgid "What personal information can I access or change?" +msgstr "" + +#: ../../pp.rst:114 +msgid "" +"You can request access to the information we have collected from you. You" +" can do this by contacting us at privacy@anastasis.lu. We will make sure " +"to provide you with a copy of the data we process about you. To comply " +"with your request, we may ask you to verify your identity. We will " +"fulfill your request by sending your copy electronically. For any " +"subsequent access request, we may charge you with an administrative fee. " +"If you believe that the information we have collected is incorrect, you " +"are welcome to contact us so we can update it and keep your data " +"accurate. Any data that is no longer needed for purposes specified in the" +" “How We Use the Information We Gather” section will be deleted after " +"ninety (90) days." +msgstr "" + +#: ../../pp.rst:128 +msgid "Data retention" +msgstr "" + +#: ../../pp.rst:130 +msgid "" +"Information entered into our bug tracker will be retained indefinitely " +"and is typically made public. We will only use it to triage the problem." +" Beyond that, we do not retain personally identifiable information about" +" our users for longer than one week." +msgstr "" + +#: ../../pp.rst:137 +msgid "Data security" +msgstr "" + +#: ../../pp.rst:139 +msgid "" +"We are committed to making sure your information is protected. We employ " +"several physical and electronic safeguards to keep your information safe," +" including encrypted user passwords, two factor verification and " +"authentication on passwords where possible, and securing connections with" +" industry standard transport layer security. You are also welcome to " +"contact us using GnuPG encrypted e-mail. Even with all these precautions," +" we cannot fully guarantee against the access, disclosure, alteration, or" +" deletion of data through events, including but not limited to hardware " +"or software failure or unauthorized use. Any information that you provide" +" to us is done so entirely at your own risk." +msgstr "" + +#: ../../pp.rst:152 +msgid "Changes and updates to privacy policy" +msgstr "" + +#: ../../pp.rst:154 +msgid "" +"We reserve the right to update and revise this privacy policy at any " +"time. We occasionally review this Privacy Policy to make sure it complies" +" with applicable laws and conforms to changes in our business. We may " +"need to update this Privacy Policy, and we reserve the right to do so at " +"any time. If we do revise this Privacy Policy, we will update the " +"“Effective Date” at the top of this page so that you can tell if it has " +"changed since your last visit. As we generally do not collect contact " +"information and also do not track your visits, we will not be able to " +"notify you directly. However, Anastasis clients may inform you about a " +"change in the privacy policy once they detect that the policy has " +"changed. Please review this Privacy Policy regularly to ensure that you " +"are aware of its terms. Any use of our Services after an amendment to our" +" Privacy Policy constitutes your acceptance to the revised or amended " +"agreement." +msgstr "" + +#: ../../pp.rst:170 +msgid "International users and visitors" +msgstr "" + +#: ../../pp.rst:172 +msgid "" +"Our Services are (currently) hosted in Germany. If you are a user " +"accessing the Services from the Switzerland, Asia, US, or any other " +"region with laws or regulations governing personal data collection, use, " +"and disclosure that differ from the laws of Germany, please be advised " +"that through your continued use of the Services, which is governed by the" +" law of the country hosting the service, you are transferring your " +"Personal Information to Germany and you consent to that transfer." +msgstr "" + +#: ../../pp.rst:183 +msgid "Questions" +msgstr "" + +#: ../../pp.rst:185 +msgid "" +"Please contact us at privacy@anastasis.lu if you have questions about our" +" privacy practices that are not addressed in this Privacy Statement." +msgstr "" + +#~ msgid "Last Updated: 11.12.2019" +#~ msgstr "" + +#~ msgid "" +#~ "This Privacy Policy describes the " +#~ "policies and procedures of Taler Systems" +#~ " SA (“we,” “our,” or “us”) pertaining" +#~ " to the collection, use, and " +#~ "disclosure of your information on our" +#~ " sites and related mobile applications " +#~ "and products we offer (the “Services”" +#~ " or “Taler Wallet”). This Privacy " +#~ "Statement applies to your personal data" +#~ " when you use our Services, and " +#~ "does not apply to online websites " +#~ "or services that we do not own " +#~ "or control." +#~ msgstr "" + +#~ msgid "" +#~ "Your privacy is important to us. " +#~ "We follow a few fundamental principles:" +#~ " We don’t ask you for personally " +#~ "identifiable information (defined below). That" +#~ " being said, your contact information, " +#~ "such as your phone number, social " +#~ "media handle, or email address " +#~ "(depending on how you contact us), " +#~ "may be collected when you communicate" +#~ " with us, for example to report " +#~ "a bug or other error related to" +#~ " the Taler Wallet. We don’t share " +#~ "your information with third parties " +#~ "except when strictly required to deliver" +#~ " you our Services and products, or" +#~ " to comply with the law. If you" +#~ " have any questions or concerns about" +#~ " this policy, please reach out to " +#~ "us at privacy@taler-systems.net." +#~ msgstr "" + +#~ msgid "" +#~ "We do our best to not collect " +#~ "any Personal Information from Taler " +#~ "Wallet users. We believe that the " +#~ "Taler Wallet never transmits personal " +#~ "information to our services without at" +#~ " least clear implied consent, and we" +#~ " only process and retain information " +#~ "with a strict business need. That " +#~ "being said, when using our Services, " +#~ "we inherently have to collect the " +#~ "following information:" +#~ msgstr "" + +#~ msgid "" +#~ "Bank account details necessary when " +#~ "receiving funds from you to top-up" +#~ " your wallet or to transfer funds " +#~ "to you when you are being paid " +#~ "via Taler. At the current experimental" +#~ " stage, only the pseudonym and " +#~ "password you entered in the bank " +#~ "demonstrator is stored." +#~ msgstr "" + +#~ msgid "" +#~ "The amounts being withdrawn or " +#~ "deposited, with associated unique transaction" +#~ " identifiers and cryptographic signatures " +#~ "authorizing the transaction. Note that " +#~ "for purchases, we cannot identify the" +#~ " buyer from the collected data, so" +#~ " when you spend money, we only " +#~ "receive non-personal information." +#~ msgstr "" + +#~ msgid "to transfer money as specified by our users (Taler transactions);" +#~ msgstr "" + +#~ msgid "" +#~ "to assist government entities in linking" +#~ " income to the underlying contract" +#~ msgstr "" + +#~ msgid "to support you using the Taler Wallet or to improve our Services" +#~ msgstr "" + +#~ msgid "" +#~ "We may share your Personal Data or" +#~ " other information about you only if" +#~ " you are a merchant receiving income," +#~ " with your bank, to the degree " +#~ "necessary to execute the payment." +#~ msgstr "" + +#~ msgid "" +#~ "We retain Personal Data to transfer " +#~ "funds to the accounts designated by " +#~ "our users. We may retain Personal " +#~ "Data only for as long as mandated" +#~ " by law and required for the " +#~ "wire transfers." +#~ msgstr "" + +#~ msgid "" +#~ "We primarily use the limited information" +#~ " we receive directly from you to " +#~ "enhance the Taler Wallet. Some ways " +#~ "we may use your Personal Information " +#~ "are to: Contact you when necessary " +#~ "to respond to your comments, answer " +#~ "your questions, or obtain additional " +#~ "information on issues related to bugs" +#~ " or errors with the Taler Wallet " +#~ "that you reported." +#~ msgstr "" + +#~ msgid "" +#~ "You can request access to the " +#~ "information we have collected from you." +#~ " You can do this by contacting " +#~ "us at privacy@taler-systems.net. We will" +#~ " make sure to provide you with " +#~ "a copy of the data we process " +#~ "about you. To comply with your " +#~ "request, we may ask you to verify" +#~ " your identity. We will fulfill your" +#~ " request by sending your copy " +#~ "electronically. For any subsequent access " +#~ "request, we may charge you with an" +#~ " administrative fee. If you believe " +#~ "that the information we have collected" +#~ " is incorrect, you are welcome to " +#~ "contact us so we can update it " +#~ "and keep your data accurate. Any " +#~ "data that is no longer needed for" +#~ " purposes specified in the “How We" +#~ " Use the Information We Gather” " +#~ "section will be deleted after ninety " +#~ "(90) days." +#~ msgstr "" + +#~ msgid "" +#~ "If you uninstall the Taler Wallet " +#~ "mobile applications from your device, or" +#~ " request that your information be " +#~ "deleted, we still may retain some " +#~ "information that you have provided to" +#~ " us to maintain the Taler Wallet " +#~ "or to comply with relevant laws." +#~ msgstr "" + +#~ msgid "" +#~ "We reserve the right to update and" +#~ " revise this privacy policy at any" +#~ " time. We occasionally review this " +#~ "Privacy Policy to make sure it " +#~ "complies with applicable laws and " +#~ "conforms to changes in our business. " +#~ "We may need to update this Privacy" +#~ " Policy, and we reserve the right " +#~ "to do so at any time. If we" +#~ " do revise this Privacy Policy, we" +#~ " will update the “Effective Date” at" +#~ " the bottom of this page so " +#~ "that you can tell if it has " +#~ "changed since your last visit. As " +#~ "we generally do not collect contact " +#~ "information and also do not track " +#~ "your visits, we will not be able" +#~ " to notify you directly. However, the" +#~ " Taler Wallet may inform you about" +#~ " a change in the privacy policy " +#~ "once it detects that the policy " +#~ "has changed. Please review this Privacy" +#~ " Policy regularly to ensure that you" +#~ " are aware of its terms. Any " +#~ "use of our Services after an " +#~ "amendment to our Privacy Policy " +#~ "constitutes your acceptance to the " +#~ "revised or amended agreement." +#~ msgstr "" + +#~ msgid "" +#~ "Our Services are hosted in Switzerland." +#~ " If you are a user accessing " +#~ "the Services from the European Union," +#~ " Asia, US, or any other region " +#~ "with laws or regulations governing " +#~ "personal data collection, use, and " +#~ "disclosure that differ from Swiss laws," +#~ " please be advised that through your" +#~ " continued use of the Services, which" +#~ " is governed by Swiss law, you " +#~ "are transferring your Personal Information " +#~ "to Switzerland and you consent to " +#~ "that transfer." +#~ msgstr "" + +#~ msgid "" +#~ "Please contact us at privacy@taler-" +#~ "systems.net if you have questions about" +#~ " our privacy practices that are not" +#~ " addressed in this Privacy Statement." +#~ msgstr "" + diff --git a/contrib/pp/pp.rst b/contrib/pp/pp.rst @@ -0,0 +1,224 @@ +Privacy Policy +============== + +Last Updated: 22.09.2021 + +This Privacy Policy describes the policies and procedures of Anastasis +SARL (“we,” “our,” or “us”) pertaining to the collection, use, and +disclosure of your information on our sites and related mobile +applications and products we offer (the “Services”). This Privacy +Statement applies to your personal data when you use our Services, and +does not apply to online websites or services that we do not own or +control. + + +Overview +-------- + +Your privacy is important to us. We follow a few fundamental +principles: We don’t ask you for personally identifiable information +(defined below). That being said, your contact information, such as +your phone number, social media handle, or email address (depending on +how you contact us), may be collected when you communicate with us, +for example to report a bug or other error related to Anastasis. We +don’t share your information with third parties except when strictly +required to deliver you our Services and products, or to comply with +the law. If you have any questions or concerns about this policy, +please reach out to us at privacy@anastasis.lu. + + +How you accept this policy +-------------------------- + +By using our Services or visiting our sites, you agree to the use, disclosure, +and procedures outlined in this Privacy Policy. + + +What personal information do we collect from our users? +------------------------------------------------------- + +The information we collect from you falls into two categories: (i) personally +identifiable information (i.e., data that could potentially identify you as an +individual) (“Personal Information”), and (ii) non-personally identifiable +information (i.e., information that cannot be used to identify who you are) +(“Non-Personal Information”). This Privacy Policy covers both categories and +will tell you how we might collect and use each type. + +We do our best to not collect any Personal Information from Anastasis +users. The detailed Personal Information Anastasis asks from you +during the regular backup and recovery process at the beginning is +never shared with us and only used to create a cryptographic account +identifier which does not allow us to recover any of your +details. This data will always remain on your own device without the +possibility of access from our side. + +That being said, when using our Services to recover key material, we may +inherently receive the following information (depending on your choice of +authentication method): + + * Bank account details necessary when receiving funds from you to authenticate via a SEPA transfer. We will store these as part of our business records for accounting, and our bank will also be legally obliged to store the details for many years according to legal retention periods. + + * Your phone number when using SMS authentication. We rely on third party providers (such as your mobile network operator) to deliver the SMS to you. These third parties will see the SMS message sent to you and could thus learn that you are using Anastasis. SMS is inherently insecure, and you should expect many governments and private parties to be able to observe these messages. However, we do not store your phone number for SMS communication on our systems, except maybe in short-term logs to diagnose errors. + + * Your e-mail address when using E-mail authentication. We rely on the Internet and your E-mail provider to deliver the E-mail to you. Internet service providers will see the E-mail message sent to you and could thus learn that you are using Anastasis. E-mail is inherently insecure, and you should expect many governments and private parties to be able to observe these messages. However, we do not store your E-mail address on our systems, except maybe in short-term logs to diagnose errors. + + * Your physical address when using postal mail authentication. We rely on external providers for printing and sending the letter to you. These providers will need to learn your address and could learn that you are using Anastasis. Physical mail has strict privacy protections by law, but governments are known to break postal secrecy. We do not store your physical address on our systems, except maybe in short-term logs to diagnose errors. + + * When you contact us. We may collect certain information if you choose to contact us, for example to report a bug or other error with the Taler Wallet. This may include contact information such as your name, email address or phone number depending on the method you choose to contact us. We strictly only use the information provided by you in these instances to answer your request or to deliver the services requested by you. + + +How we collect and process personal data +-------------------------------------- + +We may process your personal data for the following reasons: + + * to authenticate you during secret recovery + * to support you using Anastasis when you contact us + + +How we share and use the information we gather +---------------------------------------------- + +We may share your authentication data with other providers that assist +us in performing the authentication. We will try to use providers that +to the best of our knowledge respect your privacy and have good +privacy practices. We reserve the right to change authentication +providers at any time to ensure availability of our services. + +We primarily use the limited information we receive directly from you to +enhance Anastasis. Some ways we may use your Personal Information are +to: Contact you when necessary to respond to your comments, answer your +questions, or obtain additional information on issues related to bugs or +errors with the Anastasis application that you reported. + + +Agents or third party partners +------------------------------ + +We may provide your Personal Information to our employees, contractors, +agents, service providers, and designees (“Agents”) to enable them to perform +certain services for us exclusively, including: improvement and maintenance of +our software and Services. + + +Protection of us and others +--------------------------- + +We reserve the right to access, read, preserve, and disclose any information +that we reasonably believe is necessary to comply with the law or a court +order. + + +What personal information can I access or change? +------------------------------------------------- + +You can request access to the information we have collected from +you. You can do this by contacting us at privacy@anastasis.lu. We will +make sure to provide you with a copy of the data we process about +you. To comply with your request, we may ask you to verify your +identity. We will fulfill your request by sending your copy +electronically. For any subsequent access request, we may charge you +with an administrative fee. If you believe that the information we +have collected is incorrect, you are welcome to contact us so we can +update it and keep your data accurate. Any data that is no longer +needed for purposes specified in the “How We Use the Information We +Gather” section will be deleted after ninety (90) days. + + +What are your data protection rights? +------------------------------------- + +Anastasis would like to make sure you are fully aware of all of your +data protection rights. Every user is entitled to the following: + +**The right to access**: You have the right to request Anastasis for + copies of your personal data. We may charge you a small fee for this + service. + +**The right to rectification**: You have the right to request that +Anastasis correct any information you believe is inaccurate. You also +have the right to request Anastasis to complete information you +believe is incomplete. The right to erasure - You have the right to +request that Anastasis erase your personal data, under certain +conditions. + +**The right to restrict processing**: You have the right to request + that Anastasis restrict the processing of your personal data, under + certain conditions. + +**The right to object to processing**: You have the right to object to + Anastasis's processing of your personal data, under certain + conditions. + +**The right to data portability**: You have the right to request that + Anastasis transfer the data that we have collected to another + organization, or directly to you, under certain conditions. + +If you make a request, we have one month to respond to you. If you +would like to exercise any of these rights, please contact us at our +email: privacy@anastasis.lu + +You can always contact your local data protection authority to enforce +your rights. + + +Data retention +-------------- + +Information entered into our bug tracker will be retained indefinitely +and is typically made public. We will only use it to triage the +problem. Beyond that, we do not retain personally identifiable +information about our users for longer than one week. + + +Data security +------------- + +We are committed to making sure your information is protected. We employ +several physical and electronic safeguards to keep your information safe, +including encrypted user passwords, two factor verification and authentication +on passwords where possible, and securing connections with industry standard +transport layer security. You are also welcome to contact us using GnuPG +encrypted e-mail. Even with all these precautions, we cannot fully guarantee +against the access, disclosure, alteration, or deletion of data through +events, including but not limited to hardware or software failure or +unauthorized use. Any information that you provide to us is done so entirely +at your own risk. + + +Changes and updates to privacy policy +------------------------------------- + +We reserve the right to update and revise this privacy policy at any time. We +occasionally review this Privacy Policy to make sure it complies with +applicable laws and conforms to changes in our business. We may need to update +this Privacy Policy, and we reserve the right to do so at any time. If we do +revise this Privacy Policy, we will update the “Effective Date” at the top +of this page so that you can tell if it has changed since your last visit. As +we generally do not collect contact information and also do not track your +visits, we will not be able to notify you directly. However, Anastasis clients +may inform you about a change in the privacy policy once they detect that the +policy has changed. Please review this Privacy Policy regularly to ensure that +you are aware of its terms. Any use of our Services after an amendment to our +Privacy Policy constitutes your acceptance to the revised or amended +agreement. + + +International users and visitors +-------------------------------- + +Our Services are (currently) hosted in Germany. If you are a user +accessing the Services from Switzerland, Asia, US, or any other +region with laws or regulations governing personal data collection, +use, and disclosure that differ from the laws of Germany, please be +advised that through your continued use of the Services, which is +governed by the law of the country hosting the service, you are +transferring your Personal Information to Germany and you consent to +that transfer. + + +Questions +--------- + +Please contact us at privacy@anastasis.lu if you have questions about our +privacy practices that are not addressed in this Privacy Statement. diff --git a/contrib/provider-list.json b/contrib/provider-list.json @@ -0,0 +1,38 @@ +{ + "license": "GPLv3+", + "SPDX-License-Identifier": "GPL3.0-or-later", + "anastasis_provider": [ + { + "url" : "https://v1.anastasis.taler.net/", + "name" : "Bern University of Applied Sciences, Switzerland" + }, + { + "url" : "https://v1.anastasis.codeblau.de/", + "name" : "Codeblau GmbH, Germany" + }, + { + "url" : "https://v1.anastasis.lu/", + "name" : "Anastasis SARL, Luxembourg" + }, + { + "url" : "http://localhost:8086/", + "name" : "Data Loss Inc. #1", + "restricted" : "xx" + }, + { + "url" : "http://localhost:8087/", + "name" : "Data Loss Inc. #2", + "restricted" : "xx" + }, + { + "url" : "http://localhost:8088/", + "name" : "Data Loss Inc. #3", + "restricted" : "xx" + }, + { + "url" : "http://localhost:8089/", + "name" : "Data Loss Inc. #4", + "restricted" : "xx" + } + ] +} diff --git a/contrib/tos/README b/contrib/tos/README @@ -0,0 +1,58 @@ +This directory contains the terms of service (template) for exchange +operators. + + +Dependencies +============ + +Generating new Terms of Service requires Sphinx, LaTeX with babel +packages for all supported languages. On Debian, you should +at least install: + +$ apt install python3-sphinx sphinx-intl texlive-lang-german texlive-lang-english + +(NOTE: List may be incomplete.) + + +Updating the Terms of Service +============================= + +The master file with the Terms of service is 'tos.rst'. + +If you make substantial changes, you MUST change the "TOS_VERSION" +in contrib/Makefile.am to the new Etag. + +To begin the translation into other languages after editing the master +file, run + +$ make gettext + +to generate the master PO file. Then, run + +$ sphinx-intl update -p _build/locale/ -l de -l fr -l it + +to update the PO files for the various languages (extend the list of +languages as necessary). The PO files for the translators are kept +at locale/$LANG/LC_MESSAGES/tos.po for the language $LANG. + +Once all PO files have been updated with new translations, run + +$ make update-tos + +in the "contrib/" directory to generate all of the formats. The +respective make rule calls the '../update-tos.sh' script in the +contrib/ directory, which calls the 'Makefile' in the tos/ +directory for the various supported languages and file formats +and then moves the generated files to the target directory +('contrib/tos/$LANG/$VERSION.$FORMAT') + + +Adding a new language +===================== + +To add a new language $LANG, add $LANG to "TOS_LANGUAGES" in +'contrib/Makefile.am' and run + +$ sphinx-intl update -p _build/gettext -l $LANG + +to generate the PO template. diff --git a/contrib/tos/conf.py b/contrib/tos/conf.py @@ -0,0 +1,282 @@ +""" + This file is part of GNU TALER. + Copyright (C) 2014-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + + @author Florian Dold + @author Benedikt Muller + @author Sree Harsha Totakura + @author Marcello Stanisci +""" +# -*- coding: utf-8 -*- +# +# neuro documentation build configuration file, created by +# sphinx-quickstart on Sat May 31 13:11:06 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +sys.path.append(os.path.abspath('_exts')) + +#import taler_sphinx_theme + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = '1.8.5' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.todo', + 'sphinx.ext.imgmath', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +source_suffix = { + '.rst': 'restructuredtext', +} + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'tos' + +# General information about the project. +project = u'tos' +copyright = u'2014-2020 Taler Systems SA (GPLv3+ or GFDL 1.3+)' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0' +# The full version, including alpha/beta/rc tags. +release = '0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# language = "en de" + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build', '_exts', 'cf', 'prebuilt'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# default_role = "ts:type" + +locale_dirs = ['locale/'] +gettext_compact = False + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'epub' + +#html_theme_path = taler_sphinx_theme.html_theme_path() + +#html_sidebars = {'**': ['logo-text.html', 'globaltoc.html', 'searchbox.html']} + +rst_epilog = "" + +html_show_sphinx = False + +html_theme_options = { + # Set the name of the project to appear in the sidebar + "relbar1": "false", + "footer": "false", +} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +html_title = "Taler Terms of Service" + +# A shorter title for the navigation bar. Default is the same as html_title. +html_short_title = "Terms of Service" + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +# html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + #'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('tos', 'tos.tex', + 'Terms of Service', 'GNU Taler team', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# latex_appendices = ["fdl-1.3"] + +# If false, no module index is generated. +#latex_domain_indices = True + +# -- Options for manual page output --------------------------------------- + +# If true, show URL addresses after external links. +#man_show_urls = False + +# -- Options for Texinfo output ------------------------------------------- + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# -- Options for epub output ---------------------------- + +epub_basename = "tos" + +epub_title = "Terms of Service" diff --git a/contrib/tos/en/0.epub b/contrib/tos/en/0.epub Binary files differ. diff --git a/contrib/tos/en/0.html b/contrib/tos/en/0.html @@ -0,0 +1,272 @@ + + +<html lang="en"> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Terms Of Service &#8212; Taler Terms of Service</title> + <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> + <link rel="stylesheet" href="_static/epub.css" type="text/css" /> + <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script> + <script src="_static/jquery.js"></script> + <script src="_static/underscore.js"></script> + <script src="_static/doctools.js"></script> + </head><body> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body" role="main"> + + <div class="section" id="terms-of-service"> +<h1>Terms Of Service<a class="headerlink" href="#terms-of-service" title="Permalink to this headline">¶</a></h1> +<p>Last Updated: 07.09.2021</p> +<p>Welcome! Anastasis SARL (“we,” “our,” or “us”) provides a distributed +privacy-preserving backup and recovery service for key material +through our Internet presence (collectively the “Services”). Before +using our Services, please read the Terms of Service (the “Terms” or +the “Agreement”) carefully.</p> +<div class="section" id="overview"> +<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2> +<p>This section provides a brief summary of the highlights of this +Agreement. Please note that when you accept this Agreement, you are +accepting all of the terms and conditions and not just this +section. We and possibly other third parties provide Internet services +which interact with the Anastasis key backup and recovery +application. When using an application to interact with our Services, +you are agreeing to our Terms, so please read carefully.</p> +<div class="section" id="highlights"> +<h3>Highlights:<a class="headerlink" href="#highlights" title="Permalink to this headline">¶</a></h3> +<blockquote> +<div><ul class="simple"> +<li><p>You are responsible for selecting authentication methods and +policies that are adequate to protect your key material. +Any losses arising from you not being able to satisfy the +selected authentication challenges or third parties being able +successfully pass the challenges are your problem.</p></li> +<li><p>We will store your encrypted key shares and disclose them upon +successful authentication to the best of our ability within the +limitations of the law and our implementation. Our liability will +be limited to the liability limit exposed in the protocol.</p></li> +<li><p>For our Services, we may charge various fees. The specific fee structure +is provided based on the Anastasis protocol and should be shown to you when you +use an application to interact with our services. You agree and understand +that the Anastasis protocol allows for the fee structure to change.</p></li> +<li><p>You agree to not intentionally overwhelm our systems with requests and +follow responsible disclosure if you find security issues in our services.</p></li> +<li><p>We cannot be held accountable for our Services not being available due to +circumstances beyond our control. If we modify or terminate our services, +we will announce this and ensure that you can recover your key material +for at least one year before we completely terminate the Service.</p></li> +</ul> +</div></blockquote> +<p>These terms outline approved uses of our Services. If you have any +questions or comments related to this Agreement, please send us a +message to <a class="reference external" href="mailto:legal&#37;&#52;&#48;anastasis&#46;lu">legal<span>&#64;</span>anastasis<span>&#46;</span>lu</a>. If you do not agree to this Agreement, +you must not use our Services.</p> +</div> +</div> +<div class="section" id="how-you-accept-this-policy"> +<h2>How you accept this policy<a class="headerlink" href="#how-you-accept-this-policy" title="Permalink to this headline">¶</a></h2> +<p>By using our API (typically via an Anastasis-enabled application), you +acknowledge that you have read, understood, and agreed to these +Terms. We reserve the right to change these Terms at any time. If you +disagree with the change, you must simply stop using our APIs. Your +continued use of our Services following any such change will signify +your acceptance to be bound by the then current Terms. Please check +the effective date above to determine if there have been any changes +since you have last reviewed these Terms.</p> +</div> +<div class="section" id="services"> +<h2>Services<a class="headerlink" href="#services" title="Permalink to this headline">¶</a></h2> +<p>We will store your encrypted key shares (and the associated encrypted +recovery policy document) to the best of our ability and within the +limitations of the implementation. We will disclose the key shares only +after the specific authentication challenge has been passed. We will +rate-limit the use of the authentication APIs to limit brute-force +attacks.</p> +<p>We are not guaranteeing that the authentication procedures are effective. +Other parties may be able to intercept authentication messages, or you +may not be able to receive these messages anymore. You are responsible +for choosing safe authentication methods with sufficient security.</p> +<p>When using our Services, you agree to not take any action that +intentionally imposes an unreasonable load on our infrastructure. If +you find security problems in our Services, you agree to first report +them to <a class="reference external" href="mailto:security&#37;&#52;&#48;anastasis&#46;lu">security<span>&#64;</span>anastasis<span>&#46;</span>lu</a> and grant us the right to publish your +report. We warrant that we will ourselves publicly disclose any issues +reported within 1 month, and that we will not prosecute anyone +reporting security issues if they did not exploit the issue beyond a +proof-of-concept, and followed the above responsible disclosure +practice.</p> +</div> +<div class="section" id="fees"> +<h2>Fees<a class="headerlink" href="#fees" title="Permalink to this headline">¶</a></h2> +<p>You agree to pay the fees for backup and recovery operations (“Fees”) +as defined by us, which we may change from time to time. Your +Anastasis client should obtain and display applicable fees during +backup and recovery.</p> +</div> +<div class="section" id="eligibility"> +<h2>Eligibility<a class="headerlink" href="#eligibility" title="Permalink to this headline">¶</a></h2> +<p>To be eligible to use our Services, you must be able to form legally binding +contracts or have the permission of your legal guardian. By using our +Services, you represent and warrant that you meet all eligibility requirements +that we outline in these Terms.</p> +</div> +<div class="section" id="copyrights-and-trademarks"> +<h2>Copyrights and trademarks<a class="headerlink" href="#copyrights-and-trademarks" title="Permalink to this headline">¶</a></h2> +<p>The Anastasis software is released under the terms of the GNU Affero +General Public License (GNU AGPLv3+). You have the right to access, +use, and share the Anastasis application, in modified or unmodified +form. However, the Affero GPL is a strong copyleft license, which +means that any derivative works must be distributed under the same +license terms as the original software. If you have any questions, you +should review the GNU AGPL’s full terms and conditions at +<a class="reference external" href="https://www.gnu.org/licenses/agpl-3.0.en.html">https://www.gnu.org/licenses/agpl-3.0.en.html</a>. “Anastasis” itself is +a trademark of Anastasis SARL. You are welcome to use the name in +relation to implementations of the Anastasis protocol, assuming your +use is compatible with an official release from the GNU Project that +is not older than two years.</p> +</div> +<div class="section" id="limitation-of-liability-disclaimer-of-warranties"> +<h2>Limitation of liability &amp; disclaimer of warranties<a class="headerlink" href="#limitation-of-liability-disclaimer-of-warranties" title="Permalink to this headline">¶</a></h2> +<p>You understand and agree that we have no control over, and no duty to +take any action regarding: Failures, disruptions, errors, or delays in +processing that you may experience while using our Services; The risk +of failure of hardware, software, and Internet connections; The risk +of malicious software being introduced or found in the software +underlying the Anastasis implementation. You release us from all +liability related to any losses, damages, or claims arising from:</p> +<ol class="loweralpha simple"> +<li><p>user error such as forgotten security answers or loss of +control over accounts used for authentication;</p></li> +</ol> +<p>(b) server failure or data loss; +(d) bugs or other errors in the Anastasis client software; and +(e) any unauthorized third party activities, including, but not limited to,</p> +<blockquote> +<div><p>the use of viruses, phishing, brute forcing, or other means of attack +against the Anastasis client. We make no representations concerning any +Third Party Content contained in or accessed through our Services.</p> +</div></blockquote> +<p>Any other terms, conditions, warranties, or representations associated with +such content, are solely between you and such organizations and/or +individuals.</p> +<p>To the fullest extent permitted by applicable law, in no event will we +or any of our officers, directors, representatives, agents, servants, +counsel, employees, consultants, lawyers, and other personnel +authorized to act, acting, or purporting to act on our behalf +(collectively the “Anastasis Parties”) be liable to you under +contract, tort, strict liability, negligence, or any other legal or +equitable theory, for:</p> +<ol class="loweralpha simple"> +<li><p>any lost profits, data loss, cost of procurement of substitute goods or +services, or direct, indirect, incidental, special, punitive, compensatory, +or consequential damages of any kind whatsoever resulting from:</p></li> +</ol> +<blockquote> +<div><ol class="lowerroman simple"> +<li><p>your use of, or conduct in connection with, our services;</p></li> +<li><p>any unauthorized use of your wallet and/or private key due to your +failure to maintain the confidentiality of your wallet;</p></li> +<li><p>any interruption or cessation of transmission to or from the services; or</p></li> +<li><p>any bugs, viruses, trojan horses, or the like that are found in the Taler +Wallet software or that may be transmitted to or through our services by +any third party (regardless of the source of origination), or</p></li> +</ol> +</div></blockquote> +<ol class="loweralpha simple" start="2"> +<li><p>any direct damages.</p></li> +</ol> +<p>These limitations apply regardless of legal theory, whether based on tort, +strict liability, breach of contract, breach of warranty, or any other legal +theory, and whether or not we were advised of the possibility of such +damages. Some jurisdictions do not allow the exclusion or limitation of +liability for consequential or incidental damages, so the above limitation may +not apply to you.</p> +<p>Our services are provided “as is” and without warranty of any kind. To the +maximum extent permitted by law, we disclaim all representations and +warranties, express or implied, relating to the services and underlying +software or any content on the services, whether provided or owned by us or by +any third party, including without limitation, warranties of merchantability, +fitness for a particular purpose, title, non-infringement, freedom from +computer virus, and any implied warranties arising from course of dealing, +course of performance, or usage in trade, all of which are expressly +disclaimed. In addition, we do not represent or warrant that the content +accessible via the services is accurate, complete, available, current, free of +viruses or other harmful components, or that the results of using the services +will meet your requirements. Some states do not allow the disclaimer of +implied warranties, so the foregoing disclaimers may not apply to you. This +paragraph gives you specific legal rights and you may also have other legal +rights that vary from state to state.</p> +</div> +<div class="section" id="indemnity-and-time-limitation-on-claims-and-termination"> +<h2>Indemnity and Time limitation on claims and Termination<a class="headerlink" href="#indemnity-and-time-limitation-on-claims-and-termination" title="Permalink to this headline">¶</a></h2> +<p>To the extent permitted by applicable law, you agree to defend, +indemnify, and hold harmless the Anastasis Parties from and against +any and all claims, damages, obligations, losses, liabilities, costs +or debt, and expenses (including, but not limited to, attorney’s fees) +arising from: (a) your use of and access to the Services; (b) any +feedback or submissions you provide to us concerning the Anastasis +software; (c) your violation of any term of this Agreement; or (d) +your violation of any law, rule, or regulation, or the rights of any +third party.</p> +<p>You agree that any claim you may have arising out of or related to your +relationship with us must be filed within one year after such claim arises, +otherwise, your claim in permanently barred.</p> +<p>In the event of termination concerning your use of our Services, your +obligations under this Agreement will still continue.</p> +</div> +<div class="section" id="discontinuance-of-services-and-force-majeure"> +<h2>Discontinuance of services and Force majeure<a class="headerlink" href="#discontinuance-of-services-and-force-majeure" title="Permalink to this headline">¶</a></h2> +<p>We shall not be held liable for any delays, failure in performance, or +interruptions of service which result directly or indirectly from any cause or +condition beyond our reasonable control, including but not limited to: any +delay or failure due to any act of God, act of civil or military authorities, +act of terrorism, civil disturbance, war, strike or other labor dispute, fire, +interruption in telecommunications or Internet services or network provider +services, failure of equipment and/or software, other catastrophe, or any +other occurrence which is beyond our reasonable control and shall not affect +the validity and enforceability of any remaining provisions.</p> +</div> +<div class="section" id="governing-law-waivers-severability-and-assignment"> +<h2>Governing law, Waivers, Severability and Assignment<a class="headerlink" href="#governing-law-waivers-severability-and-assignment" title="Permalink to this headline">¶</a></h2> +<p>No matter where you’re located, the laws of Luxembourg will govern these +Terms. If any provisions of these Terms are inconsistent with any applicable +law, those provisions will be superseded or modified only to the extent such +provisions are inconsistent. The parties agree to submit to the ordinary +courts in Luxembourg for exclusive jurisdiction of any dispute +arising out of or related to your use of the Services or your breach of these +Terms.</p> +<p>Our failure to exercise or delay in exercising any right, power, or privilege +under this Agreement shall not operate as a waiver; nor shall any single or +partial exercise of any right, power, or privilege preclude any other or +further exercise thereof.</p> +<p>You agree that we may assign any of our rights and/or transfer, sub-contract, +or delegate any of our obligations under these Terms.</p> +<p>If it turns out that any part of this Agreement is invalid, void, or for any +reason unenforceable, that term will be deemed severable and limited or +eliminated to the minimum extent necessary.</p> +<p>This Agreement sets forth the entire understanding and agreement as to the +subject matter hereof and supersedes any and all prior discussions, +agreements, and understandings of any kind (including, without limitation, any +prior versions of this Agreement) and every nature between us. Except as +provided for above, any modification to this Agreement must be in writing and +must be signed by both parties.</p> +</div> +<div class="section" id="questions-or-comments"> +<h2>Questions or comments<a class="headerlink" href="#questions-or-comments" title="Permalink to this headline">¶</a></h2> +<p>We welcome comments, questions, concerns, or suggestions. Please send us a +message on our contact page at <a class="reference external" href="mailto:legal&#37;&#52;&#48;anastasis&#46;lu">legal<span>&#64;</span>anastasis<span>&#46;</span>lu</a>.</p> +</div> +</div> + + + <div class="clearer"></div> + </div> + </div> + </div> + <div class="clearer"></div> + </div> + </body> +</html> +\ No newline at end of file diff --git a/contrib/tos/en/0.pdf b/contrib/tos/en/0.pdf Binary files differ. diff --git a/contrib/tos/en/0.txt b/contrib/tos/en/0.txt @@ -0,0 +1,287 @@ +Terms Of Service +**************** + +Last Updated: 07.09.2021 + +Welcome! Anastasis SARL (“we,” “our,” or “us”) provides a distributed +privacy-preserving backup and recovery service for key material +through our Internet presence (collectively the “Services”). Before +using our Services, please read the Terms of Service (the “Terms” or +the “Agreement”) carefully. + + +Overview +======== + +This section provides a brief summary of the highlights of this +Agreement. Please note that when you accept this Agreement, you are +accepting all of the terms and conditions and not just this section. +We and possibly other third parties provide Internet services which +interact with the Anastasis key backup and recovery application. When +using an application to interact with our Services, you are agreeing +to our Terms, so please read carefully. + + +Highlights: +----------- + + * You are responsible for selecting authentication methods and + policies that are adequate to protect your key material. Any + losses arising from you not being able to satisfy the selected + authentication challenges or third parties being able + successfully pass the challenges are your problem. + + * We will store your encrypted key shares and disclose them upon + successful authentication to the best of our ability within the + limitations of the law and our implementation. Our liability will + be limited to the liability limit exposed in the protocol. + + * For our Services, we may charge various fees. The specific fee + structure is provided based on the Anastasis protocol and should + be shown to you when you use an application to interact with our + services. You agree and understand that the Anastasis protocol + allows for the fee structure to change. + + * You agree to not intentionally overwhelm our systems with + requests and follow responsible disclosure if you find security + issues in our services. + + * We cannot be held accountable for our Services not being + available due to circumstances beyond our control. If we modify + or terminate our services, we will announce this and ensure that + you can recover your key material for at least one year before we + completely terminate the Service. + +These terms outline approved uses of our Services. If you have any +questions or comments related to this Agreement, please send us a +message to legal@anastasis.lu. If you do not agree to this Agreement, +you must not use our Services. + + +How you accept this policy +========================== + +By using our API (typically via an Anastasis-enabled application), you +acknowledge that you have read, understood, and agreed to these Terms. +We reserve the right to change these Terms at any time. If you +disagree with the change, you must simply stop using our APIs. Your +continued use of our Services following any such change will signify +your acceptance to be bound by the then current Terms. Please check +the effective date above to determine if there have been any changes +since you have last reviewed these Terms. + + +Services +======== + +We will store your encrypted key shares (and the associated encrypted +recovery policy document) to the best of our ability and within the +limitations of the implementation. We will disclose the key shares +only after the specific authentication challenge has been passed. We +will rate-limit the use of the authentication APIs to limit brute- +force attacks. + +We are not guaranteeing that the authentication procedures are +effective. Other parties may be able to intercept authentication +messages, or you may not be able to receive these messages anymore. +You are responsible for choosing safe authentication methods with +sufficient security. + +When using our Services, you agree to not take any action that +intentionally imposes an unreasonable load on our infrastructure. If +you find security problems in our Services, you agree to first report +them to security@anastasis.lu and grant us the right to publish your +report. We warrant that we will ourselves publicly disclose any issues +reported within 1 month, and that we will not prosecute anyone +reporting security issues if they did not exploit the issue beyond a +proof-of-concept, and followed the above responsible disclosure +practice. + + +Fees +==== + +You agree to pay the fees for backup and recovery operations ("Fees") +as defined by us, which we may change from time to time. Your +Anastasis client should obtain and display applicable fees during +backup and recovery. + + +Eligibility +=========== + +To be eligible to use our Services, you must be able to form legally +binding contracts or have the permission of your legal guardian. By +using our Services, you represent and warrant that you meet all +eligibility requirements that we outline in these Terms. + + +Copyrights and trademarks +========================= + +The Anastasis software is released under the terms of the GNU Affero +General Public License (GNU AGPLv3+). You have the right to access, +use, and share the Anastasis application, in modified or unmodified +form. However, the Affero GPL is a strong copyleft license, which +means that any derivative works must be distributed under the same +license terms as the original software. If you have any questions, you +should review the GNU AGPL’s full terms and conditions at +https://www.gnu.org/licenses/agpl-3.0.en.html. “Anastasis” itself is +a trademark of Anastasis SARL. You are welcome to use the name in +relation to implementations of the Anastasis protocol, assuming your +use is compatible with an official release from the GNU Project that +is not older than two years. + + +Limitation of liability & disclaimer of warranties +================================================== + +You understand and agree that we have no control over, and no duty to +take any action regarding: Failures, disruptions, errors, or delays in +processing that you may experience while using our Services; The risk +of failure of hardware, software, and Internet connections; The risk +of malicious software being introduced or found in the software +underlying the Anastasis implementation. You release us from all +liability related to any losses, damages, or claims arising from: + +1. user error such as forgotten security answers or loss of control + over accounts used for authentication; + +(b) server failure or data loss; (d) bugs or other errors in the +Anastasis client software; and (e) any unauthorized third party +activities, including, but not limited to, + + the use of viruses, phishing, brute forcing, or other means of + attack against the Anastasis client. We make no representations + concerning any Third Party Content contained in or accessed through + our Services. + +Any other terms, conditions, warranties, or representations associated +with such content, are solely between you and such organizations +and/or individuals. + +To the fullest extent permitted by applicable law, in no event will we +or any of our officers, directors, representatives, agents, servants, +counsel, employees, consultants, lawyers, and other personnel +authorized to act, acting, or purporting to act on our behalf +(collectively the “Anastasis Parties”) be liable to you under +contract, tort, strict liability, negligence, or any other legal or +equitable theory, for: + +1. any lost profits, data loss, cost of procurement of substitute + goods or services, or direct, indirect, incidental, special, + punitive, compensatory, or consequential damages of any kind + whatsoever resulting from: + + 1. your use of, or conduct in connection with, our services; + + 2. any unauthorized use of your wallet and/or private key due to + your failure to maintain the confidentiality of your wallet; + + 3. any interruption or cessation of transmission to or from the + services; or + + 4. any bugs, viruses, trojan horses, or the like that are found in + the Taler Wallet software or that may be transmitted to or + through our services by any third party (regardless of the + source of origination), or + +2. any direct damages. + +These limitations apply regardless of legal theory, whether based on +tort, strict liability, breach of contract, breach of warranty, or any +other legal theory, and whether or not we were advised of the +possibility of such damages. Some jurisdictions do not allow the +exclusion or limitation of liability for consequential or incidental +damages, so the above limitation may not apply to you. + +Our services are provided "as is" and without warranty of any kind. To +the maximum extent permitted by law, we disclaim all representations +and warranties, express or implied, relating to the services and +underlying software or any content on the services, whether provided +or owned by us or by any third party, including without limitation, +warranties of merchantability, fitness for a particular purpose, +title, non-infringement, freedom from computer virus, and any implied +warranties arising from course of dealing, course of performance, or +usage in trade, all of which are expressly disclaimed. In addition, we +do not represent or warrant that the content accessible via the +services is accurate, complete, available, current, free of viruses or +other harmful components, or that the results of using the services +will meet your requirements. Some states do not allow the disclaimer +of implied warranties, so the foregoing disclaimers may not apply to +you. This paragraph gives you specific legal rights and you may also +have other legal rights that vary from state to state. + + +Indemnity and Time limitation on claims and Termination +======================================================= + +To the extent permitted by applicable law, you agree to defend, +indemnify, and hold harmless the Anastasis Parties from and against +any and all claims, damages, obligations, losses, liabilities, costs +or debt, and expenses (including, but not limited to, attorney’s fees) +arising from: (a) your use of and access to the Services; (b) any +feedback or submissions you provide to us concerning the Anastasis +software; (c) your violation of any term of this Agreement; or (d) +your violation of any law, rule, or regulation, or the rights of any +third party. + +You agree that any claim you may have arising out of or related to +your relationship with us must be filed within one year after such +claim arises, otherwise, your claim in permanently barred. + +In the event of termination concerning your use of our Services, your +obligations under this Agreement will still continue. + + +Discontinuance of services and Force majeure +============================================ + +We shall not be held liable for any delays, failure in performance, or +interruptions of service which result directly or indirectly from any +cause or condition beyond our reasonable control, including but not +limited to: any delay or failure due to any act of God, act of civil +or military authorities, act of terrorism, civil disturbance, war, +strike or other labor dispute, fire, interruption in +telecommunications or Internet services or network provider services, +failure of equipment and/or software, other catastrophe, or any other +occurrence which is beyond our reasonable control and shall not affect +the validity and enforceability of any remaining provisions. + + +Governing law, Waivers, Severability and Assignment +=================================================== + +No matter where you’re located, the laws of Luxembourg will govern +these Terms. If any provisions of these Terms are inconsistent with +any applicable law, those provisions will be superseded or modified +only to the extent such provisions are inconsistent. The parties agree +to submit to the ordinary courts in Luxembourg for exclusive +jurisdiction of any dispute arising out of or related to your use of +the Services or your breach of these Terms. + +Our failure to exercise or delay in exercising any right, power, or +privilege under this Agreement shall not operate as a waiver; nor +shall any single or partial exercise of any right, power, or privilege +preclude any other or further exercise thereof. + +You agree that we may assign any of our rights and/or transfer, sub- +contract, or delegate any of our obligations under these Terms. + +If it turns out that any part of this Agreement is invalid, void, or +for any reason unenforceable, that term will be deemed severable and +limited or eliminated to the minimum extent necessary. + +This Agreement sets forth the entire understanding and agreement as to +the subject matter hereof and supersedes any and all prior +discussions, agreements, and understandings of any kind (including, +without limitation, any prior versions of this Agreement) and every +nature between us. Except as provided for above, any modification to +this Agreement must be in writing and must be signed by both parties. + + +Questions or comments +===================== + +We welcome comments, questions, concerns, or suggestions. Please send +us a message on our contact page at legal@anastasis.lu. diff --git a/contrib/tos/en/0.xml b/contrib/tos/en/0.xml @@ -0,0 +1,271 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE document PUBLIC "+//IDN docutils.sourceforge.net//DTD Docutils Generic//EN//XML" "http://docutils.sourceforge.net/docs/ref/docutils.dtd"> +<!-- Generated by Docutils 0.16 --> +<document source="/research/anastasis/anastasis/contrib/tos/tos.rst"> + <section ids="terms-of-service" names="terms\ of\ service"> + <title>Terms Of Service</title> + <paragraph>Last Updated: 07.09.2021</paragraph> + <paragraph>Welcome! Anastasis SARL (“we,” “our,” or “us”) provides a distributed + privacy-preserving backup and recovery service for key material + through our Internet presence (collectively the “Services”). Before + using our Services, please read the Terms of Service (the “Terms” or + the “Agreement”) carefully.</paragraph> + <section ids="overview" names="overview"> + <title>Overview</title> + <paragraph>This section provides a brief summary of the highlights of this + Agreement. Please note that when you accept this Agreement, you are + accepting all of the terms and conditions and not just this + section. We and possibly other third parties provide Internet services + which interact with the Anastasis key backup and recovery + application. When using an application to interact with our Services, + you are agreeing to our Terms, so please read carefully.</paragraph> + <section ids="highlights" names="highlights:"> + <title>Highlights:</title> + <block_quote> + <bullet_list bullet="•"> + <list_item> + <paragraph>You are responsible for selecting authentication methods and + policies that are adequate to protect your key material. + Any losses arising from you not being able to satisfy the + selected authentication challenges or third parties being able + successfully pass the challenges are your problem.</paragraph> + </list_item> + <list_item> + <paragraph>We will store your encrypted key shares and disclose them upon + successful authentication to the best of our ability within the + limitations of the law and our implementation. Our liability will + be limited to the liability limit exposed in the protocol.</paragraph> + </list_item> + <list_item> + <paragraph>For our Services, we may charge various fees. The specific fee structure + is provided based on the Anastasis protocol and should be shown to you when you + use an application to interact with our services. You agree and understand + that the Anastasis protocol allows for the fee structure to change.</paragraph> + </list_item> + <list_item> + <paragraph>You agree to not intentionally overwhelm our systems with requests and + follow responsible disclosure if you find security issues in our services.</paragraph> + </list_item> + <list_item> + <paragraph>We cannot be held accountable for our Services not being available due to + circumstances beyond our control. If we modify or terminate our services, + we will announce this and ensure that you can recover your key material + for at least one year before we completely terminate the Service.</paragraph> + </list_item> + </bullet_list> + </block_quote> + <paragraph>These terms outline approved uses of our Services. If you have any + questions or comments related to this Agreement, please send us a + message to <reference refuri="mailto:legal@anastasis.lu">legal@anastasis.lu</reference>. If you do not agree to this Agreement, + you must not use our Services.</paragraph> + </section> + </section> + <section ids="how-you-accept-this-policy" names="how\ you\ accept\ this\ policy"> + <title>How you accept this policy</title> + <paragraph>By using our API (typically via an Anastasis-enabled application), you + acknowledge that you have read, understood, and agreed to these + Terms. We reserve the right to change these Terms at any time. If you + disagree with the change, you must simply stop using our APIs. Your + continued use of our Services following any such change will signify + your acceptance to be bound by the then current Terms. Please check + the effective date above to determine if there have been any changes + since you have last reviewed these Terms.</paragraph> + </section> + <section ids="services" names="services"> + <title>Services</title> + <paragraph>We will store your encrypted key shares (and the associated encrypted + recovery policy document) to the best of our ability and within the + limitations of the implementation. We will disclose the key shares only + after the specific authentication challenge has been passed. We will + rate-limit the use of the authentication APIs to limit brute-force + attacks.</paragraph> + <paragraph>We are not guaranteeing that the authentication procedures are effective. + Other parties may be able to intercept authentication messages, or you + may not be able to receive these messages anymore. You are responsible + for choosing safe authentication methods with sufficient security.</paragraph> + <paragraph>When using our Services, you agree to not take any action that + intentionally imposes an unreasonable load on our infrastructure. If + you find security problems in our Services, you agree to first report + them to <reference refuri="mailto:security@anastasis.lu">security@anastasis.lu</reference> and grant us the right to publish your + report. We warrant that we will ourselves publicly disclose any issues + reported within 1 month, and that we will not prosecute anyone + reporting security issues if they did not exploit the issue beyond a + proof-of-concept, and followed the above responsible disclosure + practice.</paragraph> + </section> + <section ids="fees" names="fees"> + <title>Fees</title> + <paragraph>You agree to pay the fees for backup and recovery operations (“Fees”) + as defined by us, which we may change from time to time. Your + Anastasis client should obtain and display applicable fees during + backup and recovery.</paragraph> + </section> + <section ids="eligibility" names="eligibility"> + <title>Eligibility</title> + <paragraph>To be eligible to use our Services, you must be able to form legally binding + contracts or have the permission of your legal guardian. By using our + Services, you represent and warrant that you meet all eligibility requirements + that we outline in these Terms.</paragraph> + </section> + <section ids="copyrights-and-trademarks" names="copyrights\ and\ trademarks"> + <title>Copyrights and trademarks</title> + <paragraph>The Anastasis software is released under the terms of the GNU Affero + General Public License (GNU AGPLv3+). You have the right to access, + use, and share the Anastasis application, in modified or unmodified + form. However, the Affero GPL is a strong copyleft license, which + means that any derivative works must be distributed under the same + license terms as the original software. If you have any questions, you + should review the GNU AGPL’s full terms and conditions at + <reference refuri="https://www.gnu.org/licenses/agpl-3.0.en.html">https://www.gnu.org/licenses/agpl-3.0.en.html</reference>. “Anastasis” itself is + a trademark of Anastasis SARL. You are welcome to use the name in + relation to implementations of the Anastasis protocol, assuming your + use is compatible with an official release from the GNU Project that + is not older than two years.</paragraph> + </section> + <section ids="limitation-of-liability-disclaimer-of-warranties" names="limitation\ of\ liability\ &amp;\ disclaimer\ of\ warranties"> + <title>Limitation of liability &amp; disclaimer of warranties</title> + <paragraph>You understand and agree that we have no control over, and no duty to + take any action regarding: Failures, disruptions, errors, or delays in + processing that you may experience while using our Services; The risk + of failure of hardware, software, and Internet connections; The risk + of malicious software being introduced or found in the software + underlying the Anastasis implementation. You release us from all + liability related to any losses, damages, or claims arising from:</paragraph> + <enumerated_list enumtype="loweralpha" prefix="(" suffix=")"> + <list_item> + <paragraph>user error such as forgotten security answers or loss of + control over accounts used for authentication;</paragraph> + </list_item> + </enumerated_list> + <paragraph>(b) server failure or data loss; + (d) bugs or other errors in the Anastasis client software; and + (e) any unauthorized third party activities, including, but not limited to,</paragraph> + <block_quote> + <paragraph>the use of viruses, phishing, brute forcing, or other means of attack + against the Anastasis client. We make no representations concerning any + Third Party Content contained in or accessed through our Services.</paragraph> + </block_quote> + <paragraph>Any other terms, conditions, warranties, or representations associated with + such content, are solely between you and such organizations and/or + individuals.</paragraph> + <paragraph>To the fullest extent permitted by applicable law, in no event will we + or any of our officers, directors, representatives, agents, servants, + counsel, employees, consultants, lawyers, and other personnel + authorized to act, acting, or purporting to act on our behalf + (collectively the “Anastasis Parties”) be liable to you under + contract, tort, strict liability, negligence, or any other legal or + equitable theory, for:</paragraph> + <enumerated_list enumtype="loweralpha" prefix="(" suffix=")"> + <list_item> + <paragraph>any lost profits, data loss, cost of procurement of substitute goods or + services, or direct, indirect, incidental, special, punitive, compensatory, + or consequential damages of any kind whatsoever resulting from:</paragraph> + </list_item> + </enumerated_list> + <block_quote> + <enumerated_list enumtype="lowerroman" prefix="(" suffix=")"> + <list_item> + <paragraph>your use of, or conduct in connection with, our services;</paragraph> + </list_item> + <list_item> + <paragraph>any unauthorized use of your wallet and/or private key due to your + failure to maintain the confidentiality of your wallet;</paragraph> + </list_item> + <list_item> + <paragraph>any interruption or cessation of transmission to or from the services; or</paragraph> + </list_item> + <list_item> + <paragraph>any bugs, viruses, trojan horses, or the like that are found in the Taler + Wallet software or that may be transmitted to or through our services by + any third party (regardless of the source of origination), or</paragraph> + </list_item> + </enumerated_list> + </block_quote> + <enumerated_list enumtype="loweralpha" prefix="(" start="2" suffix=")"> + <list_item> + <paragraph>any direct damages.</paragraph> + </list_item> + </enumerated_list> + <paragraph>These limitations apply regardless of legal theory, whether based on tort, + strict liability, breach of contract, breach of warranty, or any other legal + theory, and whether or not we were advised of the possibility of such + damages. Some jurisdictions do not allow the exclusion or limitation of + liability for consequential or incidental damages, so the above limitation may + not apply to you.</paragraph> + <paragraph>Our services are provided “as is” and without warranty of any kind. To the + maximum extent permitted by law, we disclaim all representations and + warranties, express or implied, relating to the services and underlying + software or any content on the services, whether provided or owned by us or by + any third party, including without limitation, warranties of merchantability, + fitness for a particular purpose, title, non-infringement, freedom from + computer virus, and any implied warranties arising from course of dealing, + course of performance, or usage in trade, all of which are expressly + disclaimed. In addition, we do not represent or warrant that the content + accessible via the services is accurate, complete, available, current, free of + viruses or other harmful components, or that the results of using the services + will meet your requirements. Some states do not allow the disclaimer of + implied warranties, so the foregoing disclaimers may not apply to you. This + paragraph gives you specific legal rights and you may also have other legal + rights that vary from state to state.</paragraph> + </section> + <section ids="indemnity-and-time-limitation-on-claims-and-termination" names="indemnity\ and\ time\ limitation\ on\ claims\ and\ termination"> + <title>Indemnity and Time limitation on claims and Termination</title> + <paragraph>To the extent permitted by applicable law, you agree to defend, + indemnify, and hold harmless the Anastasis Parties from and against + any and all claims, damages, obligations, losses, liabilities, costs + or debt, and expenses (including, but not limited to, attorney’s fees) + arising from: (a) your use of and access to the Services; (b) any + feedback or submissions you provide to us concerning the Anastasis + software; (c) your violation of any term of this Agreement; or (d) + your violation of any law, rule, or regulation, or the rights of any + third party.</paragraph> + <paragraph>You agree that any claim you may have arising out of or related to your + relationship with us must be filed within one year after such claim arises, + otherwise, your claim in permanently barred.</paragraph> + <paragraph>In the event of termination concerning your use of our Services, your + obligations under this Agreement will still continue.</paragraph> + </section> + <section ids="discontinuance-of-services-and-force-majeure" names="discontinuance\ of\ services\ and\ force\ majeure"> + <title>Discontinuance of services and Force majeure</title> + <paragraph>We shall not be held liable for any delays, failure in performance, or + interruptions of service which result directly or indirectly from any cause or + condition beyond our reasonable control, including but not limited to: any + delay or failure due to any act of God, act of civil or military authorities, + act of terrorism, civil disturbance, war, strike or other labor dispute, fire, + interruption in telecommunications or Internet services or network provider + services, failure of equipment and/or software, other catastrophe, or any + other occurrence which is beyond our reasonable control and shall not affect + the validity and enforceability of any remaining provisions.</paragraph> + </section> + <section ids="governing-law-waivers-severability-and-assignment" names="governing\ law,\ waivers,\ severability\ and\ assignment"> + <title>Governing law, Waivers, Severability and Assignment</title> + <paragraph>No matter where you’re located, the laws of Luxembourg will govern these + Terms. If any provisions of these Terms are inconsistent with any applicable + law, those provisions will be superseded or modified only to the extent such + provisions are inconsistent. The parties agree to submit to the ordinary + courts in Luxembourg for exclusive jurisdiction of any dispute + arising out of or related to your use of the Services or your breach of these + Terms.</paragraph> + <paragraph>Our failure to exercise or delay in exercising any right, power, or privilege + under this Agreement shall not operate as a waiver; nor shall any single or + partial exercise of any right, power, or privilege preclude any other or + further exercise thereof.</paragraph> + <paragraph>You agree that we may assign any of our rights and/or transfer, sub-contract, + or delegate any of our obligations under these Terms.</paragraph> + <paragraph>If it turns out that any part of this Agreement is invalid, void, or for any + reason unenforceable, that term will be deemed severable and limited or + eliminated to the minimum extent necessary.</paragraph> + <paragraph>This Agreement sets forth the entire understanding and agreement as to the + subject matter hereof and supersedes any and all prior discussions, + agreements, and understandings of any kind (including, without limitation, any + prior versions of this Agreement) and every nature between us. Except as + provided for above, any modification to this Agreement must be in writing and + must be signed by both parties.</paragraph> + </section> + <section ids="questions-or-comments" names="questions\ or\ comments"> + <title>Questions or comments</title> + <paragraph>We welcome comments, questions, concerns, or suggestions. Please send us a + message on our contact page at <reference refuri="mailto:legal@anastasis.lu">legal@anastasis.lu</reference>.</paragraph> + </section> + </section> +</document> diff --git a/contrib/tos/locale/de/LC_MESSAGES/tos.po b/contrib/tos/locale/de/LC_MESSAGES/tos.po @@ -0,0 +1,517 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2014-2020 Taler Systems SA (GPLv3+ or GFDL 1.3+) +# This file is distributed under the same license as the tos package. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2020. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: tos 0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-02-07 01:00+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.6.0\n" + +#: ../../tos.rst:2 +msgid "Terms Of Service" +msgstr "" + +#: ../../tos.rst:4 +msgid "Last Updated: 12.4.2019" +msgstr "" + +#: ../../tos.rst:6 +msgid "" +"Welcome! Taler Systems SA (“we,” “our,” or “us”) provides a payment " +"service through our Internet presence (collectively the “Services”). " +"Before using our Services, please read the Terms of Service (the “Terms” " +"or the “Agreement”) carefully." +msgstr "" + +#: ../../tos.rst:12 +msgid "Overview" +msgstr "" + +#: ../../tos.rst:14 +msgid "" +"This section provides a brief summary of the highlights of this " +"Agreement. Please note that when you accept this Agreement, you are " +"accepting all of the terms and conditions and not just this section. We " +"and possibly other third parties provide Internet services which interact" +" with the Taler Wallet’s self-hosted personal payment application. When " +"using the Taler Wallet to interact with our Services, you are agreeing to" +" our Terms, so please read carefully." +msgstr "" + +#: ../../tos.rst:23 +msgid "Highlights:" +msgstr "" + +#: ../../tos.rst:25 +msgid "" +"You are responsible for keeping the data in your Taler Wallet at all " +"times under your control. Any losses arising from you not being in " +"control of your private information are your problem." +msgstr "" + +#: ../../tos.rst:28 +msgid "" +"We will try to transfer funds we hold in escrow for our users to any " +"legal recipient to the best of our ability within the limitations of the " +"law and our implementation. However, the Services offered today are " +"highly experimental and the set of recipients of funds is severely " +"restricted." +msgstr "" + +#: ../../tos.rst:32 +msgid "" +"For our Services, we may charge transaction fees. The specific fee " +"structure is provided based on the Taler protocol and should be shown to " +"you when you withdraw electronic coins using a Taler Wallet. You agree " +"and understand that the Taler protocol allows for the fee structure to " +"change." +msgstr "" + +#: ../../tos.rst:36 +msgid "" +"You agree to not intentionally overwhelm our systems with requests and " +"follow responsible disclosure if you find security issues in our " +"services." +msgstr "" + +#: ../../tos.rst:38 +msgid "" +"We cannot be held accountable for our Services not being available due to" +" circumstances beyond our control. If we modify or terminate our " +"services, we will try to give you the opportunity to recover your funds. " +"However, given the experimental state of the Services today, this may not" +" be possible. You are strongly advised to limit your use of the Service " +"to small-scale experiments expecting total loss of all funds." +msgstr "" + +#: ../../tos.rst:45 +msgid "" +"These terms outline approved uses of our Services. The Services and these" +" Terms are still at an experimental stage. If you have any questions or " +"comments related to this Agreement, please send us a message to legal" +"@taler-systems.com. If you do not agree to this Agreement, you must not " +"use our Services." +msgstr "" + +#: ../../tos.rst:52 +msgid "How you accept this policy" +msgstr "" + +#: ../../tos.rst:54 +msgid "" +"By sending funds to us (to top-up your Taler Wallet), you acknowledge " +"that you have read, understood, and agreed to these Terms. We reserve the" +" right to change these Terms at any time. If you disagree with the " +"change, we may in the future offer you with an easy option to recover " +"your unspent funds. However, in the current experimental period you " +"acknowledge that this feature is not yet available, resulting in your " +"funds being lost unless you accept the new Terms. If you continue to use " +"our Services other than to recover your unspent funds, your continued use" +" of our Services following any such change will signify your acceptance " +"to be bound by the then current Terms. Please check the effective date " +"above to determine if there have been any changes since you have last " +"reviewed these Terms." +msgstr "" + +#: ../../tos.rst:67 +msgid "Services" +msgstr "" + +#: ../../tos.rst:69 +msgid "" +"We will try to transfer funds that we hold in escrow for our users to any" +" legal recipient to the best of our ability and within the limitations of" +" the law and our implementation. However, the Services offered today are " +"highly experimental and the set of recipients of funds is severely " +"restricted. The Taler Wallet can be loaded by exchanging fiat currencies" +" against electronic coins. We are providing this exchange service. Once " +"your Taler Wallet is loaded with electronic coins they can be spent for " +"purchases if the seller is accepting Taler as a means of payment. We are " +"not guaranteeing that any seller is accepting Taler at all or a " +"particular seller. The seller or recipient of deposits of electronic " +"coins must specify the target account, as per the design of the Taler " +"protocol. They are responsible for following the protocol and specifying " +"the correct bank account, and are solely liable for any losses that may " +"arise from specifying the wrong account. We will allow the government to " +"link wire transfers to the underlying contract hash. It is the " +"responsibility of recipients to preserve the full contracts and to pay " +"whatever taxes and charges may be applicable. Technical issues may lead " +"to situations where we are unable to make transfers at all or lead to " +"incorrect transfers that cannot be reversed. We will only refuse to " +"execute transfers if the transfers are prohibited by a competent legal " +"authority and we are ordered to do so." +msgstr "" + +#: ../../tos.rst:91 +msgid "Fees" +msgstr "" + +#: ../../tos.rst:93 +msgid "" +"You agree to pay the fees for exchanges and withdrawals completed via the" +" Taler Wallet (\"Fees\") as defined by us, which we may change from time " +"to time. With the exception of wire transfer fees, Taler transaction fees" +" are set for any electronic coin at the time of withdrawal and fixed " +"throughout the validity period of the respective electronic coin. Your " +"wallet should obtain and display applicable fees when withdrawing funds. " +"Fees for coins obtained as change may differ from the fees applicable to " +"the original coin. Wire transfer fees that are independent from " +"electronic coins may change annually. You authorize us to charge or " +"deduct applicable fees owed in connection with deposits, exchanges and " +"withdrawals following the rules of the Taler protocol. We reserve the " +"right to provide different types of rewards to users either in the form " +"of discount for our Services or in any other form at our discretion and " +"without prior notice to you." +msgstr "" + +#: ../../tos.rst:108 +msgid "Eligibility" +msgstr "" + +#: ../../tos.rst:110 +msgid "" +"To be eligible to use our Services, you must be able to form legally " +"binding contracts or have the permission of your legal guardian. By using" +" our Services, you represent and warrant that you meet all eligibility " +"requirements that we outline in these Terms." +msgstr "" + +#: ../../tos.rst:116 +msgid "Financial self-responsibility" +msgstr "" + +#: ../../tos.rst:118 +msgid "" +"You will be responsible for maintaining the availability, integrity and " +"confidentiality of the data stored in your wallet. When you setup a Taler" +" Wallet, you are strongly advised to follow the precautionary measures " +"offered by the software to minimize the chances to losse access to or " +"control over your Wallet data. We will not be liable for any loss or " +"damage arising from your failure to comply with this paragraph." +msgstr "" + +#: ../../tos.rst:126 +msgid "Copyrights and trademarks" +msgstr "" + +#: ../../tos.rst:128 +msgid "" +"The Taler Wallet is released under the terms of the GNU General Public " +"License (GNU GPL). You have the right to access, use, and share the Taler" +" Wallet, in modified or unmodified form. However, the GPL is a strong " +"copyleft license, which means that any derivative works must be " +"distributed under the same license terms as the original software. If you" +" have any questions, you should review the GNU GPL’s full terms and " +"conditions at https://www.gnu.org/licenses/gpl-3.0.en.html. “Taler” " +"itself is a trademark of Taler Systems SA. You are welcome to use the " +"name in relation to processing payments using the Taler protocol, " +"assuming your use is compatible with an official release from the GNU " +"Project that is not older than two years." +msgstr "" + +#: ../../tos.rst:140 +msgid "Your use of our services" +msgstr "" + +#: ../../tos.rst:142 +msgid "" +"When using our Services, you agree to not take any action that " +"intentionally imposes an unreasonable load on our infrastructure. If you " +"find security problems in our Services, you agree to first report them to" +" security@taler-systems.com and grant us the right to publish your " +"report. We warrant that we will ourselves publicly disclose any issues " +"reported within 3 months, and that we will not prosecute anyone reporting" +" security issues if they did not exploit the issue beyond a proof-of-" +"concept, and followed the above responsible disclosure practice." +msgstr "" + +#: ../../tos.rst:152 +msgid "Limitation of liability & disclaimer of warranties" +msgstr "" + +#: ../../tos.rst:154 +msgid "" +"You understand and agree that we have no control over, and no duty to " +"take any action regarding: Failures, disruptions, errors, or delays in " +"processing that you may experience while using our Services; The risk of " +"failure of hardware, software, and Internet connections; The risk of " +"malicious software being introduced or found in the software underlying " +"the Taler Wallet; The risk that third parties may obtain unauthorized " +"access to information stored within your Taler Wallet, including, but not" +" limited to your Taler Wallet coins or backup encryption keys. You " +"release us from all liability related to any losses, damages, or claims " +"arising from:" +msgstr "" + +#: ../../tos.rst:164 +msgid "" +"user error such as forgotten passwords, incorrectly constructed " +"transactions;" +msgstr "" + +#: ../../tos.rst:166 +msgid "server failure or data loss;" +msgstr "" + +#: ../../tos.rst:167 +msgid "unauthorized access to the Taler Wallet application;" +msgstr "" + +#: ../../tos.rst:168 +msgid "bugs or other errors in the Taler Wallet software; and" +msgstr "" + +#: ../../tos.rst:169 +msgid "" +"any unauthorized third party activities, including, but not limited to, " +"the use of viruses, phishing, brute forcing, or other means of attack " +"against the Taler Wallet. We make no representations concerning any Third" +" Party Content contained in or accessed through our Services." +msgstr "" + +#: ../../tos.rst:174 +msgid "" +"Any other terms, conditions, warranties, or representations associated " +"with such content, are solely between you and such organizations and/or " +"individuals." +msgstr "" + +#: ../../tos.rst:179 +msgid "Limitation of liability" +msgstr "" + +#: ../../tos.rst:181 +msgid "" +"To the fullest extent permitted by applicable law, in no event will we or" +" any of our officers, directors, representatives, agents, servants, " +"counsel, employees, consultants, lawyers, and other personnel authorized " +"to act, acting, or purporting to act on our behalf (collectively the " +"“Taler Parties”) be liable to you under contract, tort, strict liability," +" negligence, or any other legal or equitable theory, for:" +msgstr "" + +#: ../../tos.rst:188 +msgid "" +"any lost profits, data loss, cost of procurement of substitute goods or " +"services, or direct, indirect, incidental, special, punitive, " +"compensatory, or consequential damages of any kind whatsoever resulting " +"from:" +msgstr "" + +#: ../../tos.rst:192 +msgid "your use of, or conduct in connection with, our services;" +msgstr "" + +#: ../../tos.rst:193 +msgid "" +"any unauthorized use of your wallet and/or private key due to your " +"failure to maintain the confidentiality of your wallet;" +msgstr "" + +#: ../../tos.rst:195 +msgid "any interruption or cessation of transmission to or from the services; or" +msgstr "" + +#: ../../tos.rst:196 +msgid "" +"any bugs, viruses, trojan horses, or the like that are found in the Taler" +" Wallet software or that may be transmitted to or through our services by" +" any third party (regardless of the source of origination), or" +msgstr "" + +#: ../../tos.rst:200 +msgid "any direct damages." +msgstr "" + +#: ../../tos.rst:202 +msgid "" +"These limitations apply regardless of legal theory, whether based on " +"tort, strict liability, breach of contract, breach of warranty, or any " +"other legal theory, and whether or not we were advised of the possibility" +" of such damages. Some jurisdictions do not allow the exclusion or " +"limitation of liability for consequential or incidental damages, so the " +"above limitation may not apply to you." +msgstr "" + +#: ../../tos.rst:210 +msgid "Warranty disclaimer" +msgstr "" + +#: ../../tos.rst:212 +msgid "" +"Our services are provided \"as is\" and without warranty of any kind. To " +"the maximum extent permitted by law, we disclaim all representations and " +"warranties, express or implied, relating to the services and underlying " +"software or any content on the services, whether provided or owned by us " +"or by any third party, including without limitation, warranties of " +"merchantability, fitness for a particular purpose, title, non-" +"infringement, freedom from computer virus, and any implied warranties " +"arising from course of dealing, course of performance, or usage in trade," +" all of which are expressly disclaimed. In addition, we do not represent " +"or warrant that the content accessible via the services is accurate, " +"complete, available, current, free of viruses or other harmful " +"components, or that the results of using the services will meet your " +"requirements. Some states do not allow the disclaimer of implied " +"warranties, so the foregoing disclaimers may not apply to you. This " +"paragraph gives you specific legal rights and you may also have other " +"legal rights that vary from state to state." +msgstr "" + +#: ../../tos.rst:229 +msgid "Indemnity" +msgstr "" + +#: ../../tos.rst:231 +msgid "" +"To the extent permitted by applicable law, you agree to defend, " +"indemnify, and hold harmless the Taler Parties from and against any and " +"all claims, damages, obligations, losses, liabilities, costs or debt, and" +" expenses (including, but not limited to, attorney’s fees) arising from: " +"(a) your use of and access to the Services; (b) any feedback or " +"submissions you provide to us concerning the Taler Wallet; (c) your " +"violation of any term of this Agreement; or (d) your violation of any " +"law, rule, or regulation, or the rights of any third party." +msgstr "" + +#: ../../tos.rst:240 +msgid "Time limitation on claims" +msgstr "" + +#: ../../tos.rst:242 +msgid "" +"You agree that any claim you may have arising out of or related to your " +"relationship with us must be filed within one year after such claim " +"arises, otherwise, your claim in permanently barred." +msgstr "" + +#: ../../tos.rst:247 +msgid "Governing law" +msgstr "" + +#: ../../tos.rst:249 +msgid "" +"No matter where you’re located, the laws of Switzerland will govern these" +" Terms. If any provisions of these Terms are inconsistent with any " +"applicable law, those provisions will be superseded or modified only to " +"the extent such provisions are inconsistent. The parties agree to submit " +"to the ordinary courts in Zurich, Switzerland for exclusive jurisdiction " +"of any dispute arising out of or related to your use of the Services or " +"your breach of these Terms." +msgstr "" + +#: ../../tos.rst:258 +msgid "Termination" +msgstr "" + +#: ../../tos.rst:260 +msgid "" +"In the event of termination concerning your use of our Services, your " +"obligations under this Agreement will still continue." +msgstr "" + +#: ../../tos.rst:264 +msgid "Discontinuance of services" +msgstr "" + +#: ../../tos.rst:266 +msgid "" +"We may, in our sole discretion and without cost to you, with or without " +"prior notice, and at any time, modify or discontinue, temporarily or " +"permanently, any portion of our Services. We will use the Taler " +"protocol’s provisions to notify Wallets if our Services are to be " +"discontinued. It is your responsibility to ensure that the Taler Wallet " +"is online at least once every three months to observe these " +"notifications. We shall not be held responsible or liable for any loss of" +" funds in the event that we discontinue or depreciate the Services and " +"your Taler Wallet fails to transfer out the coins within a three months " +"notification period." +msgstr "" + +#: ../../tos.rst:277 +msgid "No waiver" +msgstr "" + +#: ../../tos.rst:279 +msgid "" +"Our failure to exercise or delay in exercising any right, power, or " +"privilege under this Agreement shall not operate as a waiver; nor shall " +"any single or partial exercise of any right, power, or privilege preclude" +" any other or further exercise thereof." +msgstr "" + +#: ../../tos.rst:285 +msgid "Severability" +msgstr "" + +#: ../../tos.rst:287 +msgid "" +"If it turns out that any part of this Agreement is invalid, void, or for " +"any reason unenforceable, that term will be deemed severable and limited " +"or eliminated to the minimum extent necessary." +msgstr "" + +#: ../../tos.rst:292 +msgid "Force majeure" +msgstr "" + +#: ../../tos.rst:294 +msgid "" +"We shall not be held liable for any delays, failure in performance, or " +"interruptions of service which result directly or indirectly from any " +"cause or condition beyond our reasonable control, including but not " +"limited to: any delay or failure due to any act of God, act of civil or " +"military authorities, act of terrorism, civil disturbance, war, strike or" +" other labor dispute, fire, interruption in telecommunications or " +"Internet services or network provider services, failure of equipment " +"and/or software, other catastrophe, or any other occurrence which is " +"beyond our reasonable control and shall not affect the validity and " +"enforceability of any remaining provisions." +msgstr "" + +#: ../../tos.rst:305 +msgid "Assignment" +msgstr "" + +#: ../../tos.rst:307 +msgid "" +"You agree that we may assign any of our rights and/or transfer, sub-" +"contract, or delegate any of our obligations under these Terms." +msgstr "" + +#: ../../tos.rst:311 +msgid "Entire agreement" +msgstr "" + +#: ../../tos.rst:313 +msgid "" +"This Agreement sets forth the entire understanding and agreement as to " +"the subject matter hereof and supersedes any and all prior discussions, " +"agreements, and understandings of any kind (including, without " +"limitation, any prior versions of this Agreement) and every nature " +"between us. Except as provided for above, any modification to this " +"Agreement must be in writing and must be signed by both parties." +msgstr "" + +#: ../../tos.rst:321 +msgid "Questions or comments" +msgstr "" + +#: ../../tos.rst:323 +msgid "" +"We welcome comments, questions, concerns, or suggestions. Please send us " +"a message on our contact page at legal@taler-systems.com." +msgstr "" + +#~ msgid "Indemntiy" +#~ msgstr "" + diff --git a/contrib/tos/tos.rst b/contrib/tos/tos.rst @@ -0,0 +1,265 @@ +Terms Of Service +================ + +Last Updated: 07.09.2021 + +Welcome! Anastasis SARL (“we,” “our,” or “us”) provides a distributed +privacy-preserving backup and recovery service for key material +through our Internet presence (collectively the “Services”). Before +using our Services, please read the Terms of Service (the “Terms” or +the “Agreement”) carefully. + +Overview +-------- + +This section provides a brief summary of the highlights of this +Agreement. Please note that when you accept this Agreement, you are +accepting all of the terms and conditions and not just this +section. We and possibly other third parties provide Internet services +which interact with the Anastasis key backup and recovery +application. When using an application to interact with our Services, +you are agreeing to our Terms, so please read carefully. + + +Highlights: +~~~~~~~~~~~ + + • You are responsible for selecting authentication methods and + policies that are adequate to protect your key material. + Any losses arising from you not being able to satisfy the + selected authentication challenges or third parties being able + successfully pass the challenges are your problem. + • We will store your encrypted key shares and disclose them upon + successful authentication to the best of our ability within the + limitations of the law and our implementation. Our liability will + be limited to the liability limit exposed in the protocol. + • For our Services, we may charge various fees. The specific fee structure + is provided based on the Anastasis protocol and should be shown to you when you + use an application to interact with our services. You agree and understand + that the Anastasis protocol allows for the fee structure to change. + • You agree to not intentionally overwhelm our systems with requests and + follow responsible disclosure if you find security issues in our services. + • We cannot be held accountable for our Services not being available due to + circumstances beyond our control. If we modify or terminate our services, + we will announce this and ensure that you can recover your key material + for at least one year before we completely terminate the Service. + +These terms outline approved uses of our Services. If you have any +questions or comments related to this Agreement, please send us a +message to legal@anastasis.lu. If you do not agree to this Agreement, +you must not use our Services. + + +How you accept this policy +-------------------------- + +By using our API (typically via an Anastasis-enabled application), you +acknowledge that you have read, understood, and agreed to these +Terms. We reserve the right to change these Terms at any time. If you +disagree with the change, you must simply stop using our APIs. Your +continued use of our Services following any such change will signify +your acceptance to be bound by the then current Terms. Please check +the effective date above to determine if there have been any changes +since you have last reviewed these Terms. + +Services +-------- + +We will store your encrypted key shares (and the associated encrypted +recovery policy document) to the best of our ability and within the +limitations of the implementation. We will disclose the key shares only +after the specific authentication challenge has been passed. We will +rate-limit the use of the authentication APIs to limit brute-force +attacks. + +We are not guaranteeing that the authentication procedures are effective. +Other parties may be able to intercept authentication messages, or you +may not be able to receive these messages anymore. You are responsible +for choosing safe authentication methods with sufficient security. + +When using our Services, you agree to not take any action that +intentionally imposes an unreasonable load on our infrastructure. If +you find security problems in our Services, you agree to first report +them to security@anastasis.lu and grant us the right to publish your +report. We warrant that we will ourselves publicly disclose any issues +reported within 1 month, and that we will not prosecute anyone +reporting security issues if they did not exploit the issue beyond a +proof-of-concept, and followed the above responsible disclosure +practice. + + +Fees +---- + +You agree to pay the fees for backup and recovery operations ("Fees") +as defined by us, which we may change from time to time. Your +Anastasis client should obtain and display applicable fees during +backup and recovery. + + +Eligibility +----------- + +To be eligible to use our Services, you must be able to form legally binding +contracts or have the permission of your legal guardian. By using our +Services, you represent and warrant that you meet all eligibility requirements +that we outline in these Terms. + + +Copyrights and trademarks +------------------------- + +The Anastasis software is released under the terms of the GNU Affero +General Public License (GNU AGPLv3+). You have the right to access, +use, and share the Anastasis application, in modified or unmodified +form. However, the Affero GPL is a strong copyleft license, which +means that any derivative works must be distributed under the same +license terms as the original software. If you have any questions, you +should review the GNU AGPL’s full terms and conditions at +https://www.gnu.org/licenses/agpl-3.0.en.html. “Anastasis” itself is +a trademark of Anastasis SARL. You are welcome to use the name in +relation to implementations of the Anastasis protocol, assuming your +use is compatible with an official release from the GNU Project that +is not older than two years. + + +Limitation of liability & disclaimer of warranties +-------------------------------------------------- + +You understand and agree that we have no control over, and no duty to +take any action regarding: Failures, disruptions, errors, or delays in +processing that you may experience while using our Services; The risk +of failure of hardware, software, and Internet connections; The risk +of malicious software being introduced or found in the software +underlying the Anastasis implementation. You release us from all +liability related to any losses, damages, or claims arising from: + +(a) user error such as forgotten security answers or loss of + control over accounts used for authentication; +(b) server failure or data loss; +(d) bugs or other errors in the Anastasis client software; and +(e) any unauthorized third party activities, including, but not limited to, + the use of viruses, phishing, brute forcing, or other means of attack + against the Anastasis client. We make no representations concerning any + Third Party Content contained in or accessed through our Services. + +Any other terms, conditions, warranties, or representations associated with +such content, are solely between you and such organizations and/or +individuals. + +To the fullest extent permitted by applicable law, in no event will we +or any of our officers, directors, representatives, agents, servants, +counsel, employees, consultants, lawyers, and other personnel +authorized to act, acting, or purporting to act on our behalf +(collectively the “Anastasis Parties”) be liable to you under +contract, tort, strict liability, negligence, or any other legal or +equitable theory, for: + +(a) any lost profits, data loss, cost of procurement of substitute goods or + services, or direct, indirect, incidental, special, punitive, compensatory, + or consequential damages of any kind whatsoever resulting from: + + (i) your use of, or conduct in connection with, our services; + (ii) any unauthorized use of your wallet and/or private key due to your + failure to maintain the confidentiality of your wallet; + (iii) any interruption or cessation of transmission to or from the services; or + (iv) any bugs, viruses, trojan horses, or the like that are found in the Taler + Wallet software or that may be transmitted to or through our services by + any third party (regardless of the source of origination), or + +(b) any direct damages. + +These limitations apply regardless of legal theory, whether based on tort, +strict liability, breach of contract, breach of warranty, or any other legal +theory, and whether or not we were advised of the possibility of such +damages. Some jurisdictions do not allow the exclusion or limitation of +liability for consequential or incidental damages, so the above limitation may +not apply to you. + +Our services are provided "as is" and without warranty of any kind. To the +maximum extent permitted by law, we disclaim all representations and +warranties, express or implied, relating to the services and underlying +software or any content on the services, whether provided or owned by us or by +any third party, including without limitation, warranties of merchantability, +fitness for a particular purpose, title, non-infringement, freedom from +computer virus, and any implied warranties arising from course of dealing, +course of performance, or usage in trade, all of which are expressly +disclaimed. In addition, we do not represent or warrant that the content +accessible via the services is accurate, complete, available, current, free of +viruses or other harmful components, or that the results of using the services +will meet your requirements. Some states do not allow the disclaimer of +implied warranties, so the foregoing disclaimers may not apply to you. This +paragraph gives you specific legal rights and you may also have other legal +rights that vary from state to state. + +Indemnity and Time limitation on claims and Termination +------------------------------------------------------- + +To the extent permitted by applicable law, you agree to defend, +indemnify, and hold harmless the Anastasis Parties from and against +any and all claims, damages, obligations, losses, liabilities, costs +or debt, and expenses (including, but not limited to, attorney’s fees) +arising from: (a) your use of and access to the Services; (b) any +feedback or submissions you provide to us concerning the Anastasis +software; (c) your violation of any term of this Agreement; or (d) +your violation of any law, rule, or regulation, or the rights of any +third party. + +You agree that any claim you may have arising out of or related to your +relationship with us must be filed within one year after such claim arises, +otherwise, your claim in permanently barred. + +In the event of termination concerning your use of our Services, your +obligations under this Agreement will still continue. + + +Discontinuance of services and Force majeure +-------------------------------------------- + +We shall not be held liable for any delays, failure in performance, or +interruptions of service which result directly or indirectly from any cause or +condition beyond our reasonable control, including but not limited to: any +delay or failure due to any act of God, act of civil or military authorities, +act of terrorism, civil disturbance, war, strike or other labor dispute, fire, +interruption in telecommunications or Internet services or network provider +services, failure of equipment and/or software, other catastrophe, or any +other occurrence which is beyond our reasonable control and shall not affect +the validity and enforceability of any remaining provisions. + + +Governing law, Waivers, Severability and Assignment +--------------------------------------------------- + +No matter where you’re located, the laws of Luxembourg will govern these +Terms. If any provisions of these Terms are inconsistent with any applicable +law, those provisions will be superseded or modified only to the extent such +provisions are inconsistent. The parties agree to submit to the ordinary +courts in Luxembourg for exclusive jurisdiction of any dispute +arising out of or related to your use of the Services or your breach of these +Terms. + +Our failure to exercise or delay in exercising any right, power, or privilege +under this Agreement shall not operate as a waiver; nor shall any single or +partial exercise of any right, power, or privilege preclude any other or +further exercise thereof. + +You agree that we may assign any of our rights and/or transfer, sub-contract, +or delegate any of our obligations under these Terms. + +If it turns out that any part of this Agreement is invalid, void, or for any +reason unenforceable, that term will be deemed severable and limited or +eliminated to the minimum extent necessary. + +This Agreement sets forth the entire understanding and agreement as to the +subject matter hereof and supersedes any and all prior discussions, +agreements, and understandings of any kind (including, without limitation, any +prior versions of this Agreement) and every nature between us. Except as +provided for above, any modification to this Agreement must be in writing and +must be signed by both parties. + + +Questions or comments +--------------------- + +We welcome comments, questions, concerns, or suggestions. Please send us a +message on our contact page at legal@anastasis.lu. diff --git a/contrib/uncrustify.cfg b/contrib/uncrustify.cfg @@ -0,0 +1,79 @@ +input_tab_size = 2 +output_tab_size = 2 + +indent_columns = 2 +indent_with_tabs = 0 +indent_case_brace = 2 +indent_label=0 + +code_width=80 +cmt_width=code_width +#cmd_width=80 + +# Leave most comments alone for now +cmt_indent_multi=false +sp_cmt_cpp_start=add + +sp_not=add + +sp_func_call_user_paren_paren=remove +sp_inside_fparen=remove +sp_after_cast=add + +ls_for_split_full=true +ls_func_split_full=true +ls_code_width=true + +# Arithmetic operations in wrapped expressions should be at the start +# of the line. +pos_arith=lead + +# Fully parenthesize boolean exprs +mod_full_paren_if_bool=false + +# Braces should be on their own line +nl_fdef_brace=add +nl_enum_brace=add +nl_struct_brace=add +nl_union_brace=add +nl_if_brace=add +nl_brace_else=add +nl_elseif_brace=add +nl_while_brace=add +nl_switch_brace=add + +# no newline between "else" and "if" +nl_else_if=remove + +nl_func_paren=remove +nl_assign_brace=remove + +# No extra newlines that cause noisy diffs +nl_start_of_file=remove +# If there's no new line, it's not a text file! +nl_end_of_file=add + +sp_inside_paren = remove + +sp_arith = add +sp_arith_additive = add + +# We want spaces before and after "=" +sp_before_assign = add +sp_after_assign = add + +# we want "char *foo;" +sp_after_ptr_star = remove +sp_between_ptr_star = remove + +# we want "if (foo) { ... }" +sp_before_sparen = add + +sp_inside_fparen = remove + +# add space before function call and decl: "foo (x)" +sp_func_call_paren = add +sp_func_proto_paren = add +sp_func_proto_paren_empty = add +sp_func_def_paren = add +sp_func_def_paren_empty = add diff --git a/contrib/uncrustify_precommit b/contrib/uncrustify_precommit @@ -0,0 +1,35 @@ +#!/bin/sh + +# use as .git/hooks/pre-commit + +exec 1>&2 + +RET=0 +changed=$(git diff --cached --name-only) +crustified="" + +for f in $changed; +do + if echo $f | grep \\.[c,h]\$ > /dev/null + then + # compare result of uncrustify with changes + # + # only change any of the invocations here if + # they are portable across all cmp and shell + # implementations ! + uncrustify -q -c uncrustify.cfg -f $f | cmp -s $f - + if test $? = 1 ; + then + crustified=" $crustified $f" + RET=1 + fi + fi +done + +if [ $RET = 1 ]; +then + echo "Run" + echo "uncrustify --replace -c uncrustify.cfg ${crustified}" + echo "before committing." +fi +exit $RET diff --git a/doc/Makefile.am b/doc/Makefile.am @@ -0,0 +1,3 @@ +# This Makefile is in the public domain + +SUBDIRS = . doxygen +\ No newline at end of file diff --git a/doc/bachelor-thesis/README.md b/doc/bachelor-thesis/README.md @@ -0,0 +1,215 @@ +# LaTeX Template for BFH Reports (TI) +This is a LaTeX template to write a report in BFH like style. + +#### Tested On + +* Ubuntu 18.04, 20.04 +* Debian 9, 10 +* Windows 10 + +## Linux Users (Ubuntu/Debian) +Linux users can use both an TeX GUI and the CLI. The GUI approach works the same as on Windows and OS X. + + * Install used LaTeX packages: +```bash +apt install texlive-base texlive-bibtex-extra texlive-binaries texlive-extra-utils texlive-formats-extra texlive-latex-base texlive-latex-extra texlive-latex-recommended texlive-pictures texlive-plain-generic texlive-science texlive-xetex + +``` + * Install LaTeX language packages: +```bash +apt install texlive-lang-english texlive-lang-french texlive-lang-german +``` + * Install used fonts packages: +```bash +apt install texlive-fonts-extra texlive-fonts-extra-links texlive-fonts-recommended texlive-font-utils +``` + * Install used build environment packages: +```bash +apt install latexmk +``` + * Install used converter packages: +```bash +apt install inkscape libcanberra-gtk-module +``` +### LaTeX GUI Editor + * [LaTeXila](https://wiki.gnome.org/Apps/GNOME-LaTeX) -- editing TeX files (Linux only) +```bash +apt install latexila +``` + * [TexStudio](https://www.texstudio.org/) -- editing TeX files (an alternative to LeTeXila) +```bash +apt install texstudio +``` +## Windows Users +### Windows Users + * MikTeX (LaTeX package manager for Windows) + * https://miktex.org/download + * Install latexmk + * If it’s not installed already, open the MikTeX Package Manager and install the `latexmk` package. + * Install perl for latexmk + * (recommended) https://strawberryperl.com/ + * (alternative) https://www.perl.org/ + * Install TeXStudio (Multi-platform -> chose appropriate installer) + * https://www.texstudio.org/ + * The LaTeX package "svg" uses inkscape to include and convert svg files on-the-fly. Download and install inkscape. + * https://inkscape.org/release/inkscape-1.0.2/ + * (Hint) If inkscape installation path is missing, add it i.e. to the environment variable "path".. + * https://tex.stackexchange.com/questions/473994/svg-and-inkscape + +## OS X Users + * MacTeX (LaTeX package manager for OS X) + + * http://www.tug.org/mactex/ + * Install latexmk + * It’s probably already installed. If not, open “TeX Live Utility”, search for “latexmk” and install it. If you prefer using the Terminal:. + ```bash + sudo tlmgr install latexmk + ``` + * Install TeXStudio (Multi-platform -> chose appropriate installer) + + * https://www.texstudio.org/ + * The LaTeX package "svg" uses Inkscape to include and convert svg files on-the-fly. Download and install Inkscape. + + * https://inkscape.org/release/inkscape-1.0.2/ + * (Hint) If Inkscape installation path is missing, add it i.e. to the environment variable "path".. + + * https://tex.stackexchange.com/questions/473994/svg-and-inkscape + +## All Platforms -- TeXStudio Settings + +Use the LaTeX GUI tool and open the main document "reportTitle.tex". Apply the settings given below when you start TeXstudio the first time. There is a file deployed with the template called ".latexmkrc" which holds some default settings. The settings are used to build the report because the selected build system will be "Latexmk". Using Latexmk has several advantages and builds on the same way whether you use the CLI or the GUI approach. + + 1. Open the configuration window *Options* -> *Configure TeXstudio* + 2. Go to *Build* -> Change Default Compiler to *latexmk* and Default Bibliography Tool to *BibTeX* + 3. In the bottom left corner, activate -> *Show Advanced Options* + * Build Options: Add as additional search paths **Log File** -> *_build* + * Build Options: Add as additional search paths **PDF File** path -> *_build* + +When you applied the configurations as described above you are ready to use the template. Use fancy buttons to edit and build the LaTeX report. For further details about the GUI tool read the reference and/or user manual. + +## CLI Usage (latexmk) +If you use cross-references, you often have to run LaTeX more than once, if you use BibTeX for your bibliography or if you want to have a glossary you even need to run external programs in-between. + +To avoid all this hassle, you should simply use [Latexmk](https://personal.psu.edu/~jcc8/software/latexmk/)! + +Latexmk is a Perl script which you just have to run once and it does everything else for you ... completely automatically. + + +Follow the instruction given below for a first test drive with Latexmk using the CLI. See the online reference of Latexmk for further information. + +Replace "FILE" with the name of the main file. To build the template use "projectReport" in place of "FILE" + +#### Running Latexmk + * In the simplest case you just have to type +```bash +latexmk +``` + *This runs LaTeX on all .tex files in the current directory using the output format specified by the configuration files.* + + * If you want to make sure to get a .pdf file as output, just mention it: +```bash +latexmk -pdf +``` + * If you want to use latex instead of pdflatex but still want a .pdf file in the end, use +```bash +latexmk -pdfps +``` + * If you want to compile only one specific .tex file in the current directory, just provide the file name: +```bash +latexmk myfile.tex +``` + * If you want to preview the resulting output file(s), just use +```bash +latexmk -pv +``` + * And now the Killer Feature: If you want Latexmk to continuously check all input files for changes and re-compile the whole thing if needed and always display the result, type +```bash +latexmk -pvc +``` +Then, whenever you change something in any of your source files and save your changes, the preview is automatically updated. But: This doesn’t work with all viewers, especially not with Adobe Reader. See the section about configuration files below for setting a suitable viewer application. + + * Of course, options can be combined, e.g. +```bash +latexmk -outdir=_build -pdf -pv myfile.tex +``` + +#### Cleaning Up + * After running LaTeX, the current directory is contaminated with a myriad of temporary files; you can get rid of them with +```bash +latexmk -c +``` + * Previous command doesn’t delete the final .pdf/.ps/.dvi files. If you want to delete those too, use +```bash +latexmk -C +``` + +#### Configuration Files +*To customize some latexmk build setting such as the default viewer for the preview, edit the file ".latexmkrc".* A snippet with some good pre-configurations for latexmk is given below. + +```bash +cat << "EOF" > .latexmkrc +## +## Adapt previewer settings +## +#$dvi_previewer = 'start xdvi -watchfile 1.5'; +#$ps_previewer = 'start gv --watch'; +#$pdf_previewer = 'start evince'; + +## +## EPS to PDF conversion hook +## +@cus_dep_list = (@cus_dep_list, "eps pdf 0 eps2pdf"); +sub eps2pdf { + system("epstopdf $_[0].eps"); + } + +## +## Set default TeX file +## +#@default_files = ('reportTitle.tex'); + +## +## Latexmk build properties +## +$pdf_mode = 1; +$bibtex_use = 1; +$latex = 'latex -interaction=nonstopmode -shell-escape'; +$pdflatex = 'pdflatex -interaction=nonstopmode -shell-escape'; + +## +## Build directory +## +$out_dir = '_build'; + +## +## Post process hooks (Linux, OS X only; For Windows install used CLI tools) +## +## Copy PDF to a sub directory named "_output" +#$success_cmd = 'mkdir -p _output && cp _build/*.pdf _output/'; +## Copy PDF to a sub directory named "_output" and create a link from top level to the PDF file +#$success_cmd = 'mkdir -p _output && cp _build/*.pdf _output/ && ln -s _output/%R.pdf'; + +## +## List of file extensions to clean up +## +$clean_ext = '%R.aux %R.dvi %R.log %R.out tex~'; +$clean_full_ext = 'bbl synctex.gz'; +EOF +``` + +## Further Reading + * [KOMA-Script Documentation](https://mirror.foobar.to/CTAN/macros/latex/contrib/koma-script/doc/scrguien.pdf) + * [KOMA-Script HTML Doc Dir](https://mirror.foobar.to/CTAN/macros/latex/contrib/koma-script/doc/) + * [Sci-Hub](https://sci-hub.st/) + * [Document Structure](https://psychology.ucsd.edu/undergraduate-program/undergraduate-resources/academic-writing-resources/writing-research-papers/research-paper-structure.html) + + * [Google Scholar](https://scholar.google.com/) + +#### Information about citation style in engineering/science + + * [IEEE Xplore](https://ieeexplore.ieee.org/Xplore/home.jsp) + +#### Information about citation style in medicine + + * [Pub-Med](https://pubmed.ncbi.nlm.nih.gov/) + diff --git a/doc/bachelor-thesis/content/.gitkeep b/doc/bachelor-thesis/content/.gitkeep diff --git a/doc/bachelor-thesis/content/abstract.tex b/doc/bachelor-thesis/content/abstract.tex @@ -0,0 +1,18 @@ +In the future, almost everything would ideally be signed with cryptographic +signatures to provide integrity, authenticity and non-repudiation. +\custind The private signing key is the most crucial component for creating a +signature and must be kept secret at all costs. But keeping a signing key +confidential is a challenging task, often underestimated in the past. +One of the main reasons for this is that any device could be compromised, +making it insecure to handle a signing key on a single device. +\custind The field of multiparty threshold signature schemes aims to address +this problem using advanced cryptographic techniques. In a threshold signature +system the signing key is distributed among $n$ parties, such that +$k \leq n$ parties are required to generate a valid signature. The additional +use of a distributed key generation ensures that the signing key is never +constituted on a single device! +\custind In this work, the authors provide a free software implementation of FROST, +a promising threshold signature scheme. +\custind As the device storing the necessary data to start a signing process +can not be trusted, a Frosix service provider always conducts an authentication +procedure before producing a signature share. +\ No newline at end of file diff --git a/doc/bachelor-thesis/content/acknowledgements.tex b/doc/bachelor-thesis/content/acknowledgements.tex @@ -0,0 +1,13 @@ +First and foremost, I would like to thank Christian Grothoff for giving me the opportunity to work on this project, +for the invaluable support whenever I needed it, for the exciting discussions during the weekly meetings and for patiently answering all my questions. +\newline I am also grateful to Markus Nufer for agreeing to be my expert. +\newline A special thanks to Tatjana Stiller, my beloved partner, for all the support and for sharing me with the study during the whole four years +and especially in the last semester. She is responsible for the naming of this project and created also the title graphic. +\newline I must thank Anastasis SARL, for the great work in developing GNU Anastasis, +which was not only a great inspiration to me, but took a lot of work off me by using existing code. +\newline I would also like to extend my thanks to Nicholas Dawes and Kasimir Rüegg for their support in the writing of this thesis. +\newline Thanks to Marc Stebler, who often stood in for me at work during this time and took a lot of the load off my shoulders. +In addition, I would like to mention René Brinkmann, who motivated me to start this degree course and also the company Geotest, +for the financial support and the time provided. +\newline Lastly, I acknowledge the use of DeepL and ChatGPT which were used to improve my English, +especially the translation of words and the use of more varied sentences. diff --git a/doc/bachelor-thesis/content/design.tex b/doc/bachelor-thesis/content/design.tex @@ -0,0 +1,526 @@ +Frosix enables secure and trustworthy signing without relying on the security of a specific device. +This is accomplished through the use of a threshold signature scheme, +where the private key is split among several entities, known as \Glspl{provider}. +\custind Additionally, a distributed key generation ensures that the private key is never instantiated in a single place, +preventing the violation of confidentiality of the private key through the compromise of a single device. + +To further enhance security, Frosix incorporates multifactor authentication +for each signing operation, allowing users to choose from various combinations of authentication factors. +\custind Considering the untrusted nature of the \Glspl{provider}, they are required to demonstrate +the integrity of the received \gls{authentication data} during the key generation. + +To reduce the attack surface of a \Gls{provider}, the long-term stored data is either salted or encrypted, +and the specific nonce and secret key used remain unknown. + +\section{Adversary Model} +Frosix is developed under the assumption of a strong and capable adversary with the ability to compromise +any user device and \Gls{provider}, but not more than $k-1$. +The adversary possesses full control over the network infrastructure, +including mobile networks, and can force companies, such as internet service providers, to cooperate. +Furthermore, the adversary is considered omnipresent throughout key generation and signing process. + +Despite the adversary's outstanding capabilities, the adversary is not able to \gls{brute-force} a salted hash +or break state-of-the-art public key cryptography. +\custind Moreover, the assumption made at the beginning is further tightened. +It is assumed, that the adversary is not able to control the devices and \Glspl{provider} involved in more than $k-1$ authentication procedures. + +Frosix relies on the presence of multiple authentication and tamper control devices, +and assumes that at least one device is not compromised. + +\section{Adaptions of FROST} +Frosix introduces modifications to the key generation and signing scheme FROST. +The changes to the original are marked in red. + +\subsubsection{Frosix Key Generation} \label{chap:frosix_key_generation} +The changes from Frosix key generation are: +\begin{itemize} + \item \textbf{Deterministic Commitments}: A \Gls{provider} uses the submitted \textit{nonce}, + the \textit{secret provider salt} and some more values (see chapter \ref{chap:rnd}) to derive the secret polynomial. + \item \textbf{Unicast Communication}: In contrast to the original FROST key generation, + all communication of a key generation process in Frosix goes through the Frosix client. + \newline This requires further adjustments: + \begin{itemize} + \item The Frosix key generation is a three round protocol. + \item The secret shares are provider-to-provider encrypted, which means that only the legitimate provider can perform the decryption. + \item The Elliptic curve Diffie-Hellmann Ephemeral (ECDHE) scheme is used for the key exchange. + \item To prevent a man-in-the-middle attack, the public key used in the ECDHE key exchange is included in the challenge of the zero knowledge proof. + \end{itemize} + \item \textbf{Authentication Data}: In order to be able to authenticate a signing request, the Frosix client computes an \gls{authentication hash} $auth\_hash$, + e.g. a salted hash over a phone number or an email address. A \Gls{provider} includes this hash to derive the commitment. + \item \textbf{Signed Group Public Key}: At the end, every \Gls{provider} stores the key data, together with the authentication hash in the database, + signs the resulting group public key and the received authentication data with its long-term public key. +\end{itemize} + +\begin{center} + \textbf{Round 1} +\end{center} + +{\large $Frosix\ Client$} \hfill {\large $\displaystyle P_{i,\ 0\ <\ i\ \leq \ n}$} +\par \textcolor{red}{\textbf{Step 1}: The \(Frosix\ client\) samples and sends a \textit{context\_string}, +together with the salted hash of the \textit{authentication data} $auth\_hash_i$ to each \(P_i\):} + +{\small $\displaystyle \textcolor{red}{(context\_string_1, ..., context\_string_1) \xleftarrow{\$}}$} + +\begin{center} + {\small $\displaystyle \textcolor{red}{(context\_string_i, auth\_hash_i) \longrightarrow} $} +\end{center} + +\textbf{Step 2}: Every $P_i$ derives a \textcolor{red}{$seed$ from the $context\_string_i$ and $auth\_hash_i$, +and uses this $seed$ to} derive $t$ values $(a_{i0}, ..., a_{i(t-1)})$. +These values are then used as coefficients to define a degree $t-1$ polynomial ($f_i(x)$): + +\begin{flushright} + {\small $\displaystyle (a_{i0}, ..., a_{i(t-1)}) \leftarrow \textcolor{red}{KDF(seed, secret\_salt_i)}$} \\ + {\small $\displaystyle f_i(x) \ =\ \sum _{j=0} ^{t-1} a_{ij}x^j$} +\end{flushright} + +\textbf{Step 3}: Every \(P_i\) \textcolor{red}{samples an \textit{ephemeral key pair} $(esk_i, epk_i)$ and} computes a proof of knowledge to the secret \(a_{i0}\): + +\begin{flushright} + {\small \textcolor{red}{$\displaystyle (esk_i, epk_i) \xleftarrow{\$}$}} \\ + {\small $\displaystyle k \xleftarrow{\$} \mathbb{Z}_q$} \\ + {\small $\displaystyle R_i \ =\ g^k$} \\ + {\small $\displaystyle c_i \ =\ H(i, "DKG-Challenge", g^{a_{i0}}, R_i, \textcolor{red}{epk_i})$} \\ + {\small $\displaystyle z_i \ =\ k + a_{i0} \cdot c_i$} \\ + {\small $\displaystyle \sigma_i \ =\ (R_i, z_i)$} +\end{flushright} + +\textbf{Step 4}: Every participant \(P_i\) computes a public commitment \(\vec{C}\): + +\begin{flushright} + {\small $\displaystyle \phi_{ij} \ =\ g^{ij}, 0 \leq j \leq t-1$} \\ + {\small $\displaystyle \vec{C_i} \ =\ \langle \phi_{i0}, ..., \phi_{i(t-1)} \rangle$} +\end{flushright} + +\textbf{Step 5}: Every \(P_i\) sends \((\vec{C_i}, \sigma_i, \textcolor{red}{epk_i})\) to \textcolor{red}{\(Frosix\ client\)}: + +\begin{center} + {\small $\displaystyle \longleftarrow (\vec{C_i}, \sigma_i, \textcolor{red}{epk_i})$} +\end{center} + +\begin{center} + \textbf{Round 2} +\end{center} + +{\large $Frosix\ Client$} \hfill {\large $\displaystyle P_{i,\ 0\ <\ i\ \leq \ n}$} +\par \textcolor{red}{\textbf{Step 1}: \(Frosix\ client\) sends \((\vec{C_l}, \sigma_l, \textcolor{red}{epk_i})\) to each \(P_i\):} + +\begin{center} + {\small \textcolor{red}{$\displaystyle (\vec{C_l}, \sigma_l, \textcolor{red}{epk_i}) \longrightarrow $}} +\end{center} + +\textbf{Step 2}: Upon receiving (\(\vec{C_l}, \sigma_l, \textcolor{red}{epk_i}\)) from \textcolor{red}{\(Frosix\ client\)}, each participant \(P_i\) verifies \(\sigma_l\): + +\begin{flushright} + {\small $\displaystyle c_l \ =\ H(l, "DKG-Challenge", \phi_{l0}, R_l, \textcolor{red}{epk_l})$} \\ + {\small $\displaystyle R_l \overset{?}{=} g^{z_l} \ \cdot \phi_{l0}^{-c_l}$} +\end{flushright} + +\par \textbf{Step 3}: Each $P_i$ \textcolor{red}{encrypts the secret shares ($l, f_i(l)$) for every other participant, +using the key $ek_{il}$ which is derived with the help of ECDHE, using another ephemeral key pair $(esk_{il}, epk_{il})$ for each other $P_i$}. +Each $P_i$ sends to \textcolor{red}{$Frosix\ client$ the encrypted secret shares $(es_{il})$ together with the ephemeral public keys $epk_{il}$}. + +\begin{flushright} + {\small \textcolor{red}{$(esk_{il}, epk_{il}) \xleftarrow{\$}$ for $l \in \{1 \ldots n\} \setminus \{i\}$}} \\ + {\small \textcolor{red}{$ek_{il} := ECDHE_{esk_{il}}(epk_i)$ for $l \in \{1 \ldots n\} \setminus \{i\}$}} \\ + {\small \textcolor{red}{$es_{il} := E_{ek_{il}}(l,f_i(l))$ for $l \in \{1 \ldots n\} \setminus \{i\}$}} +\end{flushright} + +\begin{center} + {\small $\displaystyle \longleftarrow (\textcolor{red}{es_{il}, epk_{il}})$} +\end{center} + +\begin{center} + \textbf{Round 3} +\end{center} + +{\large $Frosix\ Client$} \hfill {\large $\displaystyle P_{i,\ 0\ <\ i\ \leq \ n}$} +\par \textcolor{red}{\textbf{Step 1}: The \(Frosix\ client\) sends $(es_{li}, epk_{li})$ to each \(P_i\):} + +\begin{center} + {\small \textcolor{red}{$\displaystyle (es_{li}, epk_{li}) \longrightarrow$}} +\end{center} + +\textbf{Step 2}: Each \(P_i\) \textcolor{red}{decrypts the secret share, using their $esk_i$ in ECDHE to derive the key $ek_{il}$, and} verifies its received shares: + +\begin{flushright} + {\small \textcolor{red}{$ek_{il} := ECDHE_{esk_i}(epk_{li})$ for $l \in \{1 \ldots n\} \setminus \{i\}$}} \\ + {\small \textcolor{red}{$(l, f_i(l)) := D_{ek_{il}}(es_{il})$ for $l \in \{1 \ldots n\} \setminus \{i\}$}} \\ + {\small $\displaystyle g^{f_l(i)} \ \overset{?}{=} \ \prod _{k=0} ^{t-1} \phi_{lk}^{i^k mod \ q}$} +\end{flushright} + +\textbf{Step 3}: Each \(P_i\) calculates their long-lived private signing share \(s_i\): + +\begin{flushright} + {\small $\displaystyle s_i \ =\ \sum _{l=1} ^n f_l(i)$} +\end{flushright} + +\textbf{Step 4}: Each \(P_i\) calculates their public verification share \(Y_i\) and the group's public key \(Y\): + +\begin{flushright} + {\small $\displaystyle Y_i \ =\ g^{s_i}$} \\ + {\small $\displaystyle Y \ =\ \prod _{j=1} ^n \phi_{j0}$} +\end{flushright} + +\textbf{Step 5}: Each \(P_i\) returns the group's public key and a signature ($\phi_i$) over $(Y, auth\_hash_i)$, proving \(P_i\) was part of this key generation process +and the correct authentication data were received: + +\begin{center} + {\small \textcolor{red}{$\displaystyle \longleftarrow (Y, \phi_i)$}} +\end{center} + +\textcolor{red}{\textbf{Step 6}: \(Frosix\ client\) compares all received public keys \(Y\) and verifies the signature, +aborting if one of the public key differs from the others or if the signature verification fails.} + +Note: The values $context\_string_i$ and $auth\_hash_i$ are also submitted in round 2 and 3 to each $P_i$, +to let them compute the values $(a_{i0}, ..., a_{i(t-1)})$, without the need to store the $seed$ in the database between the rounds. + +\subsubsection{Frosix Sign} +In Frosix Sign, a challenge must be requested for every \Gls{provider}, +for which the user defined a \gls{challenge-code} based authentication. +There is therefore an additional round in Frosix Sign. +\newline Besides this, the only difference from the original FROST scheme occurs in round 2 (round 1 from FROST). +\custind The modification includes the hash of the message into the commitments. +By making this change, the message becomes linked to the \gls{commitment}, +preventing the commitment from being used for any other message. + +\begin{center} + \textbf{Round 1} +\end{center} + +{\large \(Frosix\ Client\)} \hfill {\large $\displaystyle P_{i\ \in \ S}$} +\par \textbf{Step 1}: The user chooses the set $S$, \(k\ of\ n\) parties and the $Frosix\ client$ hashes the input message: + +{\small $\displaystyle S\ =\ \{P_1, ..., P_k\},\ 0 < P_i \leq n$} \\ +{\small \textcolor{red}{$\displaystyle h \ =\ H(\$message)$}} + +\textbf{Step 2}: \textcolor{red}{$Frosix\ client$ sends to each $P_i$ a \textit{challenge request}, +containing the hash of the message ($h$), the hash of the encryption key ($enc\_key\_h_i$), +the \gls{authentication method} ($auth\_method_i$), the authentication data ($auth\_data_i$) and the authentication nonce ($auth\_nonce_i$). +But only if a challenge-code based authentication method was chosen for $P_i$ during the key generation.} + +\begin{center} + {\small \textcolor{red}{$\displaystyle (h, enc\_key\_h_i, auth\_method_i, auth\_data_i, auth\_nonce_i) \longrightarrow$}} +\end{center} + +\textbf{Step 3}: \textcolor{red}{Each $P_i$ verifies if the hash of over $auth\_data_i$ and $auth\_nonce_i$ match the stored $auth\_hash_i$ +and responds with the $challenge\_code_i$ over a different channel, depending on the $auth\_method_i$, to the submitted address in $auth\_data_i$.} + +\begin{flushright} + {\small \textcolor{red}{$\displaystyle H(auth\_data_i, auth\_nonce_i, "FROSIX") \overset{?}{=} auth\_hash$}} +\end{flushright} + +\begin{center} + {\small $\displaystyle challenge\_code_i \longrightarrow $} +\end{center} + +\begin{center} + \textbf{Round 2} +\end{center} + +{\large \(Frosix\ Client\)} \hfill {\large $\displaystyle P_{i\ \in \ S}$} +\par \textbf{Step 1}: \textcolor{red}{The $Frosix\ client$ sends to each $P_i$ the hash of the message ($h$) and the +challenge data ($challenge\_data_i$), which is either a hash of the received $challenge\_code_i$ or the signature over $h$ (using the secret answer to derive the signing key, see chapter~\ref{chap:rnd}), in case of a \textit{security question}.} + +\begin{center} + {\small \textcolor{red}{$\displaystyle (h, challenge\_data_i) \longrightarrow$}} +\end{center} + +\textbf{Step 2}: Each $P_i$ first verifies the $challenge\_data_i$ and then samples \textcolor{red}{a random $seed_i$. +Together with the hash of the message, each \(P_i\) derives} two random commitment values and send those back to the \(Frosix\ client\). + +\begin{flushright} + {\small \textcolor{red}{$\displaystyle seed_i \xleftarrow{\$}$}} \\ + {\small $\displaystyle (d_i,e_i) \textcolor{red}{\leftarrow KDF(m, seed_i)}$} \\ + {\small $\displaystyle (D_i,E_i) \ = \ (g^{d_i},g^{e_i})$} +\end{flushright} + +\begin{center} + {\small $\displaystyle \longleftarrow (D_i,E_i)$} +\end{center} + +\begin{center} + \textbf{Round 3} +\end{center} + +{\large \(Frosix\ Client\)} \hfill {\large $\displaystyle P_{i\ \in \ S}$} + +\textbf{Step 1}: The $Frosix\ client$ fetches all commitments, builds the set $B \ = \ \langle i,D_i,E_i \rangle, i \in S$ and sends $B$ together with the hash of the message to all $P_i$ in $S$. + +{\small $\displaystyle B \ =\ \langle ( i,D_{i} ,E_{i})\rangle _{i}{}_{\in }{}_{S}$} + +\begin{center} + {\small $\displaystyle ( h,\ B) \longrightarrow $} +\end{center} + +\textbf{Step 2}: After receiving $(h,\ B)$, each $P_i$ validates the message $h$, and then checks $D_l,E_l \in \mathbb{G}^*$ for each commitment in $B$, aborting if either check fails. + +\textbf{Step 3}: Each $P_i$ then computes the set of binding values. + +\begin{flushright} + {\small $\displaystyle p_l \ = \ H_1(l,h,B), l \in S$} +\end{flushright} + +\textbf{Step 4}: Each $P_i$ then derives the group commitment $R$ and the challenge $c$. + +\begin{flushright} + {\small $\displaystyle R \ =\ \prod _{l \in S} D_l \cdot (E_l)^{\rho_l}$} \\ + {\small $\displaystyle c \ =\ H_2(R,Y,h)$} +\end{flushright} + +\textbf{Step 5}: Each $P_i$ computes their response $z_i$ using their long-lived secret share $s_i$ +\textcolor{red}{and the secret values ($d_i, e_i$) which each $P_i$ computes with the help of the temporary stored $seed_i$ from round 2}. + +\begin{flushright} + {\small $\displaystyle z_i \ =\ d_i + (e_i \cdot \rho_i) + \lambda_i \cdot s_i \cdot c$} +\end{flushright} + +\textbf{Step 6}: Each $P_i$ securely deletes the \textcolor{red}{$seed_i$} from their local storage, and then returns $z_i$ to $Frosix\ client$. + +\begin{center} + {\small $\displaystyle \longleftarrow z_i$} +\end{center} + +\textbf{Step 7}: The $Frosix\ client$ calculates the set of binding values \(p_l\), +the set of individual commitments \(R_l\), the group commitment \(R\) and the challenge \(c\). +With these values, the $Frosix\ client$ verifies the validity of each response \(z_i\). + +{\small $\displaystyle p_l \ =\ H_1(l,h,B), l \in S$} \\ +{\small $\displaystyle R_l \ =\ D_l \cdot (E_l)^{\rho_l}, l \in S$} + +{\small $\displaystyle R \ =\ \prod _{l \in S} R_l$} \\ +{\small $\displaystyle c \ =\ H_2(R,Y,h)$} + +{\small $\displaystyle g^{z_i} \overset{?}{=} R_i \cdot Y_i^{c \cdot \lambda_i}$} + +\textbf{Step 8}: The $Frosix\ client$ computes the resulting signature. + +{\small $\displaystyle z = \sum z_i$} \\ +{\small $\displaystyle \sigma \ =\ (R, z)$} + +\section{Authentication} +Frosix uses multifactor authentication to enhance the security and trustworthiness of its signing process. +Users are required to provide evidence of their identity, such as answering a security question or submitting a challenge-code. +\custind With this approach, Frosix pays tribute to pseudonymous communication on the Internet, +as a \Gls{provider} cannot distinguish a legitimate request from a malicious one. +For both requests, the sender is simply an IP address. + +\subsubsection{Challenge-Code} +The majority of authentication methods employed in Frosix involve the requesting of challenge-codes over various communication channels +such as SMS, email or postal mail. +Those authentication methods are based on the codebase of GNU Anastasis \cite{anastasis}. + +\subsubsection{Security Question}\label{chap:sec_question} +One of the objectives of Frosix is to establish trust in the public key, +generated at the end of a Frosix key generation process. +A \Gls{provider} is therefore required to proof the ability to recognize our secret answer. +However, secret answers are typically low in entropy and vulnerable to brute-force attacks. +To address this issue, Frosix introduces a small tweak, compared to the implementation of GNU Anastasis \cite{anastasis}. +\custind It is crucial to consider the potential points an adversary may have to gain knowledge of the secret answer. +If the adversary can observe the secret answer being entered, cryptographic protection becomes ineffective. +\custind Furthermore, it is important to ensure that knowledge of the hash alone cannot authenticate a signing request, +and transmitting the non-hashed value is not a viable option. +\custind Lastly, the authentication should be highly coupled with the hash of the message. +It should not be possible for a man-in-the-middle to change the message during transmission without being noticed. + +To fulfill the first requirement, during the key generation process, +a \Gls{provider} receives a salted hash, which then is stored in the database. +The use of a high-entropy nonce used as \gls{salt} makes it difficult to brute-force. +\custind Because this salted hash is signed by the \Gls{provider} at the end of the key generation process, +the same value has to be stored in the Frosix signing document, together with the salt. +To make brute-forcing more challenging, Frosix utilizes a password-based key derivation function (PBKDF). +Users have the option to specify a difficulty level or allow the system to adapt the difficulty +based on the hardware the Frosix client is running on, during key generation. +\custind To address the other concerns, Frosix incorporates simple public key cryptography. +The Frosix client derives a private key from the secret answer, using a PBKDF, +computes the corresponding public key, and uses it to sign the message, along with the nonce. +When a \Gls{provider} receives the triple consisting of the message, the signature and the public key, +it verifies the signature against the message, hashes the public key, and compares it to the stored hash. +If the hashes match, the challenge is considered to be solved, and that request is authorized. +\custind Consequently, only the hash of the derived public key is submitted, signed, +and stored in the Frosix signing document during a key generation process. + +\section{Derivation from Randomness} \label{chap:rnd} +Frosix relies on randomness in different places, but otherwise tries to derive as much as possible deterministically. +Many cryptographic systems rely on good randomness, however, using bad, or predictable, randomness can lead to disastrous results. +The Frosix approach therefore reduces potential attack surfaces. +\custind In the figures below, the development of the different derived and random values is shown. + +Figure~\ref{fig:figure_legend} shows the legend of the following figures from this chapter. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_entropy_figures_legend} + \caption{Legend for Figure~\ref{fig:client_entropy} to Figure~\ref{fig:provider_sig_entropy}} + \label{fig:figure_legend} +\end{figure} + + +\subsection{Frosix Key Generation} +From a \Gls{provider} 's perspective, all three rounds of Frosix key generation are implemented with full determinism, +ensuring that the outcomes of these rounds remain consistent. +As a result, the corresponding REST endpoints associated with each round exhibit idempotent behavior, +meaning that repeated requests to these endpoints will have the same effect as a single request, +without causing any unintended side effects. + +\subsubsection{Frosix Client} +Figure~\ref{fig:client_entropy} shows the different derivations of the Frosix client during a key generation process. +\par First, the Frosix client gets high-entropy seeds from each \Gls{provider}. +Afterwards, it puts the \textit{provider entropy}, together with \textit{local entropy}, +in a key derivation function (KDF) and derives the \textit{client masterkey}, +as well as all \textit{context strings}. +Finally, with the masterkey, the Frosix client derives the \textit{authentication nonces} and the \textit{pre encryption keys}. +A \textit{pre encryption key} will later serve as nonce to derive an \textit{encryption key}. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_client_entropy} + \caption{Frosix client: derivations during a key generation process} + \label{fig:client_entropy} +\end{figure} + +The hashing of the authentication data depends on the selected authentication method. +\par If the selected authentication method involves the requesting and submitting of a challenge-code (Figure~\ref{fig:client_auth_hash}), +the \textit{authentication data}, such as a phone number or an email address, +is hashed together with an \textit{\gls{authentication nonce}}, resulting in the \textit{authentication hash}. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_client_authentication_hash} + \caption{Hashing of authentication data of challenge-code based authentication methods} + \label{fig:client_auth_hash} +\end{figure} + +In case of a security question (Figure~\ref{fig:client_auth_hash_question}), +the \textit{secret answer} and the \textit{authentication nonce} are thrown in a password-based key derivation function (PBKDF). +The \textit{amplifier value} adjusts the number of iterations the PBKDF will perform to derive a \textit{seed}. +A higher value means more iteration and therefore higher costs for a brute-force attack. +\custind From this seed, first a private signing key is created and afterwards the corresponding public key computed. +This public key is then hashed, which results in the \textit{authentication hash}. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_client_authentication_hash_question} + \caption{Hashing of authentication data of a security question} + \label{fig:client_auth_hash_question} +\end{figure} + +\subsubsection{Frosix Service Provider} +The derivation of entropy is exactly the same for a \textit{POST /dkg-commitment} and a \textit{POST /dkg-shares} request (Figure~\ref{fig:provider_dkg-commitment_entropy}). +Since the key generation process at a \Gls{provider} does not involve further randomness, +virtually every bit of a request is included to prevent different requests resulting in the same key. + +First, the submitted \textit{public keys} of all participating \Glspl{provider}, +the \textit{threshold value} and the \Gls{provider} 's index are hashed. +A change in the main parameters during a key generation process, +such as changing the \textit{threshold value} or replacing a \Gls{provider}, +will result in a different hash and consequently in a different \textit{secret value} and different \textit{coefficients} +and the key generation will fail. +\custind This hash, the \textit{context string}, the \textit{authentication hash} and the \textit{secret provider salt} +(a value which is only known to one \Gls{provider} and which can be reused for many key generations), +serves as input in a key derivation function which outputs the \textit{provider masterkey}. +From this masterkey, the \Gls{provider} derives the \textit{secret value}, +the \textit{coefficients} of the degree t-1 polynomial and computes the \textit{commitment values}. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_provider_dkg-commitment_entropy} + \caption{Derivations of a \textit{POST /dkg-commitment} or \textit{POST /dkg-shares} request} + \label{fig:provider_dkg-commitment_entropy} +\end{figure} + +In the last round of a key generation process, the resulting key data, +consisting of a private and a public key, is encrypted and stored in the \Gls{provider} 's database. +Figure~\ref{fig:provider_dkg-key_entropy} shows how the \textit{encryption key} is derived from the +\textit{pre encryption key}, the \Gls{provider} \textit{index}, the \textit{public provider salt} +(a value which can be publicly received with a \textit{GET /config} request), +and the resulting public key. +The hash of the encryption key serves as identifier for the entry in the database. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_provider_dkg-key_entropy} + \caption{Derivations of a \textit{POST /dkg-key} request} + \label{fig:provider_dkg-key_entropy} +\end{figure} + +Not mentioned are the proof of knowledge of the \textit{secret value} and the ephemeral keys, +used in the ECDHE for securely transmitting the secret shares. +Both procedures use random values and are described in the Frosix key generation protocol (Chapter~\ref{chap:frosix_key_generation}). + +\subsection{Frosix Sign} +Originally, it was planned to derive the nonce, used in the generation of signatures, deterministically from the message and the private key share, analogous to EdDSA. +However, research has shown that this procedure cannot be applied to threshold signatures and that it can result in a key disclosure \cite{10.5555/648120.747057}, +due to the possibility of nonce reuse if an adversary has control over at least one \Gls{provider} and the Frosix client. + +Therefore, a \Gls{provider} uses the hash over a random \textit{commitment seed}, combined with the \textit{hash of the message} to derive the \textit{secret values} +and consequently the \textit{commitment}. +\custind Both \textit{commitment values} and the \textit{encryption key hash} are hashed together, +and the resulting value serves as identifier to store the \textit{commitment seed} in the database (Figure~\ref{fig:provider_sig_entropy}). + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_provider_sign_entropy} + \caption{Derivations of a \textit{POST /sig-commitment} request} + \label{fig:provider_sig_entropy} +\end{figure} + +In the second round of Frosix sign, all \textit{commitments} are sent to each \Gls{provider}, +together with the \textit{message hash} and the individual \textit{encryption key}. + +A \Gls{provider} now does the following to restore the \textit{secret values}: +\begin{itemize} + \item hashes the \textit{encryption key} and finds the key data in the database, including its index number + \item takes the matching commitment from the commitment list and together with \textit{encryption key hash} computes the database identifier of the \textit{commitment seed} + \item loads and immediately deletes the \textit{commitment seed} from the database (no reuse!) + \item restores the secret values with the help of the \textit{message hash} and the \textit{commitment seed} +\end{itemize} + +\newpage +\section{Long-term Stored Data} +The storage of long-term data introduces potential attack vectors. +One of the key objectives of Frosix was to reduce and prevent such attack vectors. + +\subsubsection{Frosix Signing Document} +With access to the Frosix signing document, an adversary learns how many and which \Glspl{provider} are involved, +the corresponding encryption keys, which authentication methods are used and the associated authentication data, +such as phone number, email address, security question (not the answer). +The Frosix signing document should therefore be stored carefully - like a signing key! +\custind In contrast to a signing key from a single-signer signature scheme, this knowledge is not enough to issue arbitrary signatures, +because of the enforced authentication of each signing request. + +\subsubsection{Frosix Service Provider Database} +If the database of a \Gls{provider} is leaked, an adversary gains little knowledge: +\begin{itemize} + \item \textbf{Authentication Data}: The authentication data stored at a \Gls{provider} is a salted hash. + Without knowledge of the corresponding nonce, it is nearly infeasible for an adversary to brute-force it, + even if the set of all possible values is small (e.g. a phone number). + \item \textbf{Key Data}: The key data, consisting of the private key and public key, is stored encrypted. + Without knowledge of the encryption key used, it is infeasible for an adversary with limited computational power + to break the encryption. + \newline Even though the public key does not actually need to be protected, storing it in plaintext + would allow an adversary to correlate different encrypted key data from the same or from different \Glspl{provider}. + \item \textbf{Index}: With access to the \Glspl{provider} index in a signing group, + an adversary can conclude which entries do not belong to each other (if two entries have the same index number). +\end{itemize} + +\section{Trusted Public Key} +Since the Frosix adversary model assumes that any device could be compromised, +an adversary could substitute the authentication data during key generation. +Therefore, after a key generation is complete, each \Gls{provider} signs +the resulting public key and the received authentication data with its own long-term private key. +This signature can then be verified by the user (on a non-compromised device). +\custind In addition, it can be proven to third persons which \Glspl{provider} are part of a signing group +represented by the public key. +This can establish further trust in the signatures, if the involved \Glspl{provider} are well-known. + +\section{Delete Key Data} +In the design of Frosix, the deletion of data stored at a \Gls{provider} can be accomplished by providing only the hash of the encryption key. +As a result, it may be beneficial to back up URLs of the selected \Glspl{provider}, together with hashes of the encryption key, +in case the Frosix signing document is lost. +\custind Since access to a particular device, cell phone number or email address is not given forever, +the deletion does not need an authentication, which a user then might not be able to fulfill anymore. + +Despite the inconvenience of the potential unavailability to create signatures, +this is far less significant compared to the risk of losing control over the private key shares. +And generating a new key is not a big effort with Frosix (perhaps the distribution of the public key is). diff --git a/doc/bachelor-thesis/content/future_work.tex b/doc/bachelor-thesis/content/future_work.tex @@ -0,0 +1,31 @@ +With the current implementation, Frosix generates a distributed key among up to 254 parties +and with a threshold value of up to 253. +Together with the different implemented authentication methods, Frosix provides +a new solution for the problem of how to keep a private signing key confidential. +\custind Frosix is free software and the source code accessible for everyone \cite{frosix}. + +Due to the time limitation, the current implementation status of Frosix is far from +production-ready or safe to use. +There are some known (and unknown) bugs, the memory management needs to be reworked, +the garbage collection of the database is not implemented, +the documentation of the functions and structs is not complete, +there are still unused fragments of GNU Anastasis left, +and not everything is implemented exactly as described in this thesis. +Just to mention a few remaining issues to tackle. + +I plan to continue working on Frosix after submitting this thesis. + +Besides these imperfections, there are additional ideas to enhance Frosix +and ideally enable it to be used as a commercial service. +These ideas could serve as interesting topics for other student projects: + + +\begin{itemize} \label{future_work} + \item develop a GUI or a more user-friendly application + \item integrate GNU Taler as a payment system + \item support alternative signature algorithms in libfrost + \item implement deterministic threshold signatures + \item add further authentication methods (like TOTP) + \item do performance optimization (e.g. \cite{zcash:perf}) + \item elaborate the possibility to properly detect and exclude misbehaving \Glspl{provider} +\end{itemize} diff --git a/doc/bachelor-thesis/content/glossary.tex b/doc/bachelor-thesis/content/glossary.tex @@ -0,0 +1,89 @@ +\newglossaryentry{provider}{ + name={Frosix service provider}, + description={A webserver, running Frosix on it and exposing a RESTful interface to interact with.}, + plural={frosix service providers} +} + +\newglossaryentry{client}{ + name={Frosix client}, + description={A client application which allows a user to use Frosix.} +} + +\newglossaryentry{nonce}{ + name={nonce}, + description={A nonce (number used once) is usually a high-entropy value which is only used once.}, + plural={nonces} +} + +\newglossaryentry{secret server salt}{ + name={secret server salt}, + description={A secret, high entropy source of entropy of a Frosix service provider to protect against a bad random attack.}, + plural={secret server salts} +} + +\newglossaryentry{trusted dealer}{ + name={trusted dealer}, + description={A trusted dealer is a central party in a secret sharing system, who divides and distributes a secret and has therefore, as the only one, knowledge of the secret.} +} + +\newglossaryentry{zero knowledge proof}{ + name={zero knowledge proof}, + description={Proof of knowing a secret, without revealing any information of it. Also known under the term proof of knowledge.} +} + +\newglossaryentry{salt}{ + name={salt}, + description={A salt is used in hashing as an additional high-entropy input to prevent brute-forcing of e.g. a low-entropy value.}, + plural={salts} +} + +\newglossaryentry{brute-force}{ + name={brute-force}, + description={Brute-forcing is a exhaustive search, in which every possible value is checked for example to crack a password.}, +} + +\newglossaryentry{struct}{ + name={struct}, + description={In the programming language C, structs are a way to group several related variables into one object.}, + plural={structs}, +} + +\newglossaryentry{authentication hash}{ + name={authentication hash}, + description={In Frosix, the authentication hash is stored in the database from a Frosix service provider. It is used to authenticate a user.} +} + +\newglossaryentry{authentication data}{ + name={authentication data}, + description={Authentication data includes data like a phone number or an email address (where to send a challenge-code).} +} + +\newglossaryentry{authentication method}{ + name={authentication method}, + description={The authentication method describes the method which is used to authenticate a user.} +} + +\newglossaryentry{authentication nonce}{ + name={authentication nonce}, + description={In order to hash the authentication data, which normally has a low-entropy value as input, another high-entropy input is needed.} +} + +\newglossaryentry{context string}{ + name={context string}, + description={A context string is similar to a seed or a nonce. It serves as high-entropy input for hashing or key derivation.} +} + +\newglossaryentry{seed}{ + name={seed}, + description={A seed is used in a function which outputs pseudorandom data, e.g. a key derivation function, to achieve the same output several times.} +} + +\newglossaryentry{commitment}{ + name={commitment}, + description={With a commitment, it is possible to fix a specific value without revealing it. Useful in multiparty computation, if each participant should contribute a value, without knowing beforehand what the other values are.} +} + +\newglossaryentry{challenge-code}{ + name={challenge-code}, + description={In order to use authentication with different devices and over different channels, a challenge-code is used. If the user can present the correct challenge-code, he is authorized to issue a signature.} +} +\ No newline at end of file diff --git a/doc/bachelor-thesis/content/implementation.tex b/doc/bachelor-thesis/content/implementation.tex @@ -0,0 +1,668 @@ +Even though C has lost popularity in recent years, Frosix is free software, written in C. +Like every programming language, C has advantages and disadvantages. +\custind The main disadvantages are the non-trivial memory management, +the freedom that everything is just a pointer and that out-of-bound memory access is not checked. +\custind Therefore, during the development of Frosix, care was taken to create \glspl{struct} where possible, +to check against the size of an array before accessing it and to ensure, +that no substantial memory leak or use after free happens. +Especially, because it is nearly impossible for someone with little development experience to write bug-free software, +minor and probably also major bugs exist. +\custind On the other hand, Frosix benefits a lot from rich and performant libraries written in C. +As it was planned from the beginning to reuse parts of the codebase from GNU Anastasis, +the question of the programming language has never arisen. + +\par Frosix is organized in different components. Figure~\ref{fig:system_comp_overview} gives an overview. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_system_overview} + \caption{System components overview} + \label{fig:system_comp_overview} +\end{figure} + +The middle box contains the core implementation of Frosix, including the implementation of the FROST protocol in the library libfrost. +At the bottom are the utilized external libraries +and on the left side are the implemented authentication methods. + +\subsubsection{External Libraries} +\begin{itemize} + \item \textbf{Libsodium}: Sodium is a modern library for virtually all cryptographic tasks. + It is a fork of the well-known library NaCl, which is a library with implementations from reputable cryptographers. + And most importantly for Frosix, Sodium provides an implementation of the ristretto255 group. \cite{libsodium} + \item \textbf{Libgnunet}: GNUnet is not just a library, it is a framework for P2P networking. However, + Frosix only uses some of GNUnet's foundational libraries, and not the actual P2P networking stack. + The GNUnet libraries offer great functionality for logging, parsing from and to JSON (based on Libjansson) + and provide some elegant to use cryptographic operations without the need of additional wrapping (like with Libsodium). \cite{libgnunet} + \item \textbf{Libcurl}: libcurl provides functionalities for the basic network communication between a Frosix client and a \Gls{provider}. + It is probably the most used library for this purpose. \cite{libcurl} + \item \textbf{Libmicrohttpd}: The \Glspl{provider} are based on GNU libmicrohttpd, a very lightweight HTTP server offering great flexibility. \cite{libmicrohttpd} + \item \textbf{PostgreSQL}: PostgreSQL serves as the database for a \Gls{provider}. + It is open source, widely used and is being developed very actively, making it the default choice if there are no special requirements. \cite{postgresql} + \item \textbf{Libjansson}: Jansson is nowadays the standard library in C based project, if they work with JSON data. + Frosix not only utilizes Jansson to parse from and to JSON data in the network communication, but also to parse all from the CLI incoming and outputting data. \cite{libjansson} + \item \textbf{Libtaler}: Despite the payment system GNU Taler not being integrated in the current version of Frosix, + some of GNU Taler's libraries are already in use because they provide additional useful functionalities. \cite{Libtaler} +\end{itemize} + +\newpage +\section{System Architecture} \label{chap:sys_arch} +A general overview of the architecture of Frosix is shown in Figure~\ref{fig:system_arch_overview}. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_system_architecture} + \caption{System architecture overview} + \label{fig:system_arch_overview} +\end{figure} + +\subsubsection{Frosix Files} +Every input and output to and from the CLI is in the form of JSON data, except purely informative messages. +Those inputs and outputs can be stored in various files, depending on the purpose. +The files can then easily be manipulated, copied, deleted or even encrypted, by hand or in an automated way. + +\subsubsection{Command Line Interface} +The command line interface (CLI) of Frosix exposes all implemented functionality in various commands. +It allows the use of Frosix from a shell. + +\subsubsection{Libfrosix}\label{impl:libfrosix} +In libfrosix, the input from the CLI is parsed into the different variables. +Furthermore, libfrosix is responsible for gathering and maintaining all required information, +triggering the necessary calls from the RESTclient, and handling the corresponding responses. +Also libfrosix provides the link to libfrost, in order to execute the steps from the FROST protocol. +If something goes wrong, it is up to libfrosix to abort the current command, +clean up everything and return a useful error message back to the user. + +\subsubsection{Libfrost} +Libfrost is the implementation of the FROST protocol and provides an easy-to-use high level API. +Thus, libfrosix does not have to care about the complicated cryptography hidden inside the FROST protocol. +The second part of libfrost is the low level wrapping of all utilized functions from libsodium. +This is due to the fact that libsodium does not offer any typing, and therefore it is not safe to use. + +\subsubsection{RESTclient}\label{impl:restclient} +As a counterpart to every REST endpoint from the Frosix Webserver, +there is an implementation of a REST startpoint on the client side. +The RESTclient encodes the inputs of each request into JSON data and sends them to a REST endpoint from a \Gls{provider}. +If there is a response, the RESTclient is responsible to decode the JSON data and pass them back to libfrosix. + +\subsubsection{REST API} +The REST API is an instantiation of libmicrohttpd. It receives and forwards incoming request to the matching handlers. + +\subsubsection{REST API Handlers} +There is a separate handler for every implemented REST endpoints. +The handlers include the main logic of a \Gls{provider}. +They parse the incoming data, do the verification, load and store data from the database via the database plugin +and use libfrost in order to perform the FROST protocol computation. + +\subsubsection{Database} +Frosix uses a PostgreSQL database to store data both for a short duration and long-term. +All stored data have an expiration date and get eventually deleted with a regularly running garbage collection task. + +\newpage +\section{Server Architecture} +A \Gls{provider} consists of a small webserver (libmicrohttpd), +some handlers to handle all the different requests, +a plugin to access the database, +a plugin to handle the different authentication methods +and libfrost (Figure~\ref{fig:server_arch}). + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_server_architecture} + \caption{Frosix server architecture} + \label{fig:server_arch} +\end{figure} + +\subsubsection{REST API} +For detailed information about Frosix's RESTful API, see appendix A. + +\subsubsection{Handlers} +\textbf{Terms Handler} +\newline Returns the terms of service of a \Gls{provider}. +At the moment, the terms of service are just a copy of the terms of service from GNU Anastasis \cite{anastasis} and must be adapted to Frosix. + +\textbf{Config Handler} +\newline Returns the current configuration of a \Gls{provider}. +This includes supported authentication methods, public provider salt, public key and some more information. + +\textbf{Seed Handler} +\newline Returns some high entropy bytes, which are used in the key generation process, +thus counteracting bad PRNG on client side. + +\textbf{KeyGen Handlers} +\newline There are three sub-handlers, one for each round of the key generation protocol: +\begin{itemize} + \item \textbf{Dkg-Commitment}: Returns a deterministically derived commitment. + Whereas the size of such a request increases linearly with number of participating providers, + the size of a commitment increases linearly with the selected threshold value. + \item \textbf{Dkg-Shares}: Returns an encrypted share of a private key share for each other \Gls{provider}. + The size of this request can quickly escalate, because it linearly depends on the number of + participating \Glspl{provider}, as well as on the selected threshold value. + The size of the response, however, depends solely on the number of involved \Glspl{provider}. + \item \textbf{Dkg-Key}: Returns the final public key and a signature over the public key and the submitted authentication value (a salted hash). + Only the size of the request to this handler is dependent on the number of involved \Glspl{provider}. +\end{itemize} + +\textbf{Sign Handlers} +\newline There are two sub-handlers, one for each phase: +\begin{itemize} + \item \textbf{Sig-Commitment}: Returns a commitment, derived from a random nonce and the submitted hash of the message. + \item \textbf{Sig-Share}: Returns the signature share. + Both the size of the request and of the response are linearly increasing with the threshold value. +\end{itemize} + +\textbf{Key Delete Handler} +\newline Allows to delete the data stored in the database of a \Gls{provider}. + +\textbf{Challenge Handler} +\newline A request to this handler triggers a challenge-code, which then is transferred over a different channel, +if the hash of the submitted authentication data and nonce match the stored hash. + +\newpage +\section{Database} +The database schema of Frosix is shown below (Figure~\ref{fig:database_schema}). + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_database} + \caption{Frosix database schema} + \label{fig:database_schema} +\end{figure} + +\subsubsection{Key} +This is the main table where all essential data used for authentication and signing is stored. + +\begin{itemize} + \item \textbf{key\_id}: The identifier of key data is the hash of the encryption key. + \newline \(key\_id = H(encryption\_key)\) + \item \textbf{identifier}: The identifier is a unique number in the signing group. + This value can be anything between 1 and 254. + \item \textbf{expiration}: The expiration field contains a number indication for how many years a \Gls{provider} should store this entry. + \item \textbf{encryption\_nonce}: This field represents a high entropy value used in the encryption of the \textit{enc\_key\_data}. + \item \textbf{enc\_key\_data}: This is the encrypted key data, including the private key share and the public key. + \item \textbf{auth\_data}: The authentication data is a salted hash over a phone number, email address, postal address etc. +\end{itemize} + +\subsubsection{Public\_Commitments} +The table \textit{pbulic\_commitments} is only used during a key generation process and stores the commitments of all other \Glspl{provider} between round 2 and 3. + +\begin{itemize} + \item \textbf{dkg\_id}: The identifier of some stored public commitments is the ID of the corresponding \textit{dkg-*} request (see appendix~\ref{appendix_a} for more details about the request IDs). + \item \textbf{time\_stamp}: The time when the entry was created. + This value helps to clean up the database regularly, without deleting entries which are still in use. + \item \textbf{commitments}: This field stores a blob with the commitments from all other \Glspl{provider}. +\end{itemize} + +Since there can be up to 253 commitments with each up to 253 values with a size of 32 bytes each, this table can grow quickly. +However, the usage of these values is for a short time, a few minutes at most. +This table should therefore be cleaned up regularly. + +\subsubsection{Challengecode} +In contrast to the table \textit{public\_commitment}, the lifetime of these values is measured in days. +This table and the corresponding logic are part of the code reuse from GNU Anastasis \cite{anastasis} and are therefore not explained in detail. + +\subsubsection{Seed} +This table stores the \gls{seed} which was used to generate the commitment in the first round of the signing process. +As with the entries in \textit{public\_commitments}, these values have a very short lifetime. + +\begin{itemize} + \item \textbf{seed\_id}: The identifier of a seed is the hash over the hash of the encryption key and the hash of the message + \newline \(seed\_id = H(H(encryption\_key) || H(message))\). + \item \textbf{seed}: This field contains the freshly and random generated high entropy nonce. + \item \textbf{time\_stamp}: The time when this entry was created. + This value helps to clean up the database regularly, without deleting entries which are still in use. +\end{itemize} + +There is no relation between the tables, because every table serves a different purpose +and the identifier of an entry is related to corresponding data in a request, except for the key table. + +\section{Authentication Methods} +Following authentication methods are implemented, or can at least be integrated with little effort\footnote{The approach of challenge-code based authentication methods is implemented.}: + +\begin{itemize} + \item \textbf{SMS}: A challenge-code, together with the hash of the message is sent in an SMS to the matching phone number. + \item \textbf{Email}: A challenge-code, together with the hash of the message is sent in an email to the matching email address. + \item \textbf{Mail}: A challenge-code, together with the hash of the message is sent in a letter to the matching postal address. + \item \textbf{Security Question}: Does not involve a challenge-code (see chapter \ref{chap:sec_question}). +\end{itemize} + +\section{Client Architecture} +Frosix client consists out of three modules: +\begin{itemize} + \item Command line interface (CLI) + \item Libfrosix + \item RESTclient +\end{itemize} + +The functionalities and responsibilities of Libfrosix and the RESTclient are already explained in chapter \ref{chap:sys_arch}. + +\subsubsection{Command Line Interface} +The command line interface exposes useful commands to the user. + +\textbf{Available Commands and Options} +\begin{itemize} + \item \textit{keygen -o signing\_document(.json) < providerlist(.json)}: + \newline takes a valid Frosix providerlist as input and does a distributed key generation with all listed \Glspl{provider} + \item \textit{export-pk -o public\_key(.json) < signing\_document(.json)}: + \newline takes a Frosix signing document and exports the public key and the signature of each involved \Gls{provider} + \item \textit{verify-pk < public\_key(.json)}: + \newline verifies all signatures in a Frosix public key document + \item \textit{request-challenge -a '{"provider\_index":\$provider\_index}' -m "\$message" < signing\_document(.json)}: + \newline requests a challenge-code for the specified \Gls{provider} + \item \textit{sign -a '{"1":"\$solution1", "2":"\$solution2"}' -m "\$message" -o signature(.json) < signing\_document(.json)}: + \newline signs a message with the provided challenge-codes or a secret answer + \item \textit{verify -m "\$message" < signature(.json)}: + \newline verifies a signature against a message + \item \textit{delete-key < signing document(.json)}: + \newline requests the deletion of all data stored at each \Gls{provider} from the provided Frosix signing document + \item \textit{-o} (output): + \newline writes the output to a file with the specified name + \item \textit{-a} (argument): + \newline submit further arguments, formatted as JSON + \item \textit{-m} (message): + \newline submit a message to sign (will always get hashed before signing) + \item \textit{<} (shell input redirection): + \newline redirects the content of a document as input to a command + \item \textit{\$provider\_index}: + \newline a value between 1 and 254 and must match a \Gls{provider} in the signing document (value is written without surrounding quotes) + \item \$message: + \newline the message that is to be signed or is already signed +\end{itemize} + +\subsection{Frosix Files} +This chapters explains the use and structure of all Frosix files in detail. + +\newpage +\subsubsection{Frosix Provider List} +A Frosix providerlist includes all necessary information to start a Frosix key generation process. +Below is a minimal example of a \textit{Frosix providerlist}. +Technically, it is possible to use only two \Glspl{provider} and a \textit{threshold-value} of 1. + +\begin{verbatim} +{ + "threshold": 2, + "expiration": 5, + "providers": [ + { + "url": "$PROVIDER_URL_1", + "public_key": "$PROVIDER_PUBLIC_KEY_1", + "auth_method": "sms", + "auth_data": "$PHONE_NUMBER" + }, + { + "url": "$PROVIDER_URL_2", + "public_key": "$PROVIDER_PUBLIC_KEY_2", + "auth_method": "question", + "auth_data": "The answer to life, the universe and everything", + "auth_answer": "42" + }, + { + "url": "$PROVIDER_URL_3", + "public_key": "$PROVIDER_PUBLIC_KEY_3", + "auth_method": "email", + "auth_data": "$EMAIL_ADDRESS", + } + ] +} +\end{verbatim} + +\textbf{Frosix provider list values explained} +\begin{itemize} + \item \textit{threshold}: defines the \textit{threshold-value}. + \item \textit{expiration}: number of years until a \Gls{provider} should delete the private key share + \item \textit{providers}: list of chosen \Glspl{provider}, defines total number of providers at the same time (\Glspl{provider} may occur more than once) + \item \textit{url}: URL under which this \Gls{provider} is reachable + \item \textit{public\_key}: public key of this provider, to detect if someone is impersonating a \Gls{provider} + \item \textit{auth\_method}: method, which should be used for authentication before issuing a signature + \item \textit{auth\_data}: corresponding authentication data like a phone number or an email address + \item opt. \textit{auth\_answer}: hash of a public key, which is derived from the secret answer (only if auth\_method is \textit{question}). +\end{itemize} + +Note: A \textit{Frosix provider list} can and should be deleted after being successfully used in Frosix key generation, +as it can contain sensitive information like the secret answer to a security questions. + +\subsubsection{Frosix Signing Document} +A Frosix signing document contains all data required to request a challenge, +to start a Frosix sign process, to export the public key +and to delete the private key shares. + +\begin{verbatim} + { + "public_key": "$PUBLIC_KEY", + "number_of_participants": 3, + "threshold": 2, + "providers": [ + { + "provider_index": 1, + "provider_name": "$PROVIDER_NAME_1", + "backend_url": "$PROVIDER_URL_1", + "encryption_key": "$ENCRYPTION_KEY_1", + "auth_method": "sms", + "auth_data": "$PHONE_NUMBER", + "auth_nonce": "$AUTH_NONCE_1", + "auth_hash": "$AUTH_HASH_1", + "provider_signature": "$PROVIDER_SIGNATURE_1" + "provider_public_key": "$PROVIDER_PUBLIC_KEY_1" + }, + { + "provider_index": 2, + "provider_name": "$PROVIDER_NAME_2", + "backend_url": "$PROVIDER_URL_2", + "encryption_key": "$ENCRYPTION_KEY_2", + "auth_method": "question", + "auth_data": "The answer to life, the universe and everything", + "auth_nonce": "$AUTH_NONCE_2", + "auth_hash": "$AUTH_HASH_2", + "provider_signature": "$PROVIDER_SIGNATURE_2" + "provider_public_key": "$PROVIDER_PUBLIC_KEY_2" + }, + { + "provider_index": 3, + "provider_name": "$PROVIDER_NAME_3", + "backend_url": "$PROVIDER_URL_3", + "encryption_key": "$ENCRYPTION_KEY_3", + "auth_method": "email", + "auth_data": "$EMAIL_ADDRESS", + "auth_nonce": "$AUTH_NONCE_3", + "auth_hash": "$AUTH_HASH_3", + "provider_signature": "$PROVIDER_SIGNATURE_3" + "provider_public_key": "$PROVIDER_PUBLIC_KEY_3" + } + ] + } +\end{verbatim} + +\textbf{Frosix signing document's values explained}\label{sec:frosix_sign_document} +\begin{itemize} + \item \textit{public\_key}: the public key to verify a signature, which is created based on this Frosix signing document + \item \textit{number\_of\_participants}: this value could technically be omitted and is therefore just supporting information + \item \textit{threshold}: the threshold value which defines how many \Glspl{provider} are necessary to issue a valid signature + \item \textit{providers}: list of all \Glspl{provider}, which were part of the preceding Frosix key generation + \item \textit{provider\_index}: unique identifier of this \Gls{provider} in the group, a value between 1 and 254 + \item \textit{provider\_name}: human-friendly name of this \Gls{provider} (received from a GET /config request) + \item \textit{backend\_url}: URL under which this provider is reachable + \item \textit{encryption\_key}: this value is needed to find the corresponding encrypted private key share in the \Gls{provider} 's database and to decrypt that private key share + \item \textit{auth\_method}: method which is used for authentication + \item \textit{auth\_data}: data which corresponds to the chosen authentication method (phone number, email address, etc.) + \item \textit{auth\_nonce}: salt which was used to hash the authentication data + \item \textit{auth\_hash}: the resulting hash + \newline Note: the authentication hash is not absolutely necessary, + except in the case where the authentication method is of type \textit{question} (since we do not want to store the secret answer in plaintext). + \item \textit{provider\_signature}: a signature from this \Gls{provider} over the \textit{public\_key} and the \textit{auth\_hash} + \item \textit{provider\_public\_key}: public key of this \Gls{provider} which was used to create the \textit{provider\_signature} (public key is received from a GET /config request) +\end{itemize} + +Note: Even though the security of Frosix does not rely on the confidentiality of a Frosix signing document, +it should nevertheless be handled like a private signing key. +In case of disclosure, the chosen \textit{threshold-value} and the possible combinations of authentication methods can still provide strong protection. +\custind In such a situation we recommend deleting all private key shares as soon as possible and creating a new Frosix signing document. + +\subsubsection{Frosix Public key} +Unlike a Frosix signing document, a Frosix public key can and should be published to those, who have to verify our signatures. + +\begin{verbatim} +{ + "public_key": "$PUBLIC_KEY", + "providers": [ + { + "provider_name": "$PROVIDER_NAME_1", + "backend_url": "$PROVIDER_URL_1", + "auth_hash": "$AUTH_HASH_1", + "provider_signature:" "$PROVIDER_SIGNATURE_1", + "provider_public_key": "$PROVIDER_PUBLIC_KEY_1" + }, + { + "provider_name": "$PROVIDER_NAME_2", + "backend_url": "$PROVIDER_URL_2", + "auth_hash": "$AUTH_HASH_2", + "provider_signature:" "$PROVIDER_SIGNATURE_2", + "provider_public_key": "$PROVIDER_PUBLIC_KEY_2" + }, + { + "provider_name": "$PROVIDER_NAME_3", + "backend_url": "$PROVIDER_URL_3", + "auth_hash": "$AUTH_HASH_3", + "provider_signature:" "$PROVIDER_SIGNATURE_3", + "provider_public_key": "$PROVIDER_PUBLIC_KEY_3" + } + ] +} +\end{verbatim} + +For a detailed description of those values, see chapter~\ref{sec:frosix_sign_document}. + +\subsubsection{Frosix signature} + +\begin{verbatim} +{ + "message_hash": "$MESSAGE_HASH", + "public_key": "$PUBLIC_KEY", + "signature_r": "$SIGNATURE_R_VALUE", + "signature_z": "$SIGNATURE_Z_VALUE" +} +\end{verbatim} + +\textbf{Frosix signature's values explained}\ +\begin{itemize} + \item \textit{message\_hash}: hash of the signed message, not absolutely necessary since the message itself always has to be submitted to verify the signature + \item \textit{public\_key}: public key which corresponds to the private key used to issue this signature + \item \textit{signature\_r}: first part of the signature + \item \textit{signature\_z}: second part of the signature +\end{itemize} + +Note: Both signature values could be combined in one value in the future. + +\newpage +\section{Application Flow} +In this section, the different flows between the Frosix client and the \Glspl{provider} are described. + +\subsubsection{Distributed Key Generation} +Figure \ref{fig:dkg_sequence} illustrates the Frosix key generation process. +The specifications of the REST endpoints can be found in appendix~\ref{appendix_a}. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_dkg_sequence} + \caption{Frosix distributed key generation sequence} + \label{fig:dkg_sequence} +\end{figure} + +\begin{enumerate} + \item The user prepares a Frosix Providerlist as input to frosix-cli keygen. + \item The Frosix client requests the server configuration from each \Glspl{provider} (GET /config), which includes information like supported authentication methods, public key to verify a providers signature and the \Gls{provider} public server salt. + If one of the \Glspl{provider} doesn't respond to this request the Frosix client will abort the process. + \item After positive feedback was received from all \Glspl{provider}, the Frosix client asks each \Gls{provider} for a seed (GET /seed), to be used as partial source of entropy (see chapter design). + \item Before starting the first round of the distributed key generation process, the Frosix client combines all received seeds together with local entropy and derives all \glspl{nonce} and context strings. + \item In the first round of the distributed key generation process, the Frosix client requests every \Gls{provider} to derive a commitment from the submitted \gls{context string} and the \Gls{provider} \gls{secret server salt} (POST /dkg-commitment). + \item Next, the Frosix client distributes all commitments to every participating \Gls{provider}, requesting the \Glspl{provider} to send the encrypted secret shares (POST /dkg-shares). + \item Afterwards, those encrypted shares have to be ordered and the Frosix client transmits to each \Gls{provider} only the secret shares targeted to this specific provider (POST /dkg-key), initiating round three. + \item Last, the Frosix client receives the public key of the generated key pair and a signature from each provider, checks if every public key is the same and verifies the signature over the public key and the authentication data, aborting if it fails. + \item At the end, the Frosix client outputs a Frosix signing document. +\end{enumerate} + +\subsubsection{Request Challenge} +Figure \ref{fig:challenge_sequence} illustrates a single challenge request sequence. This request must be done for each challenge-code independently. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_request-challenge_sequence} + \caption{Frosix request challenge sequence} + \label{fig:challenge_sequence} +\end{figure} + +\begin{enumerate} + \item The user provides the \textit{Frosix signing document} and specifies from which listed \Gls{provider} a challenge-code should be requested for which message. + \item The Frosix client sends the challenge request and if the submitted authentication data matches the salted hash stored at the \Gls{provider}, a challenge-code is issued (POST /auth-challenge). +\end{enumerate} + +\subsubsection{Distributed Signing} +Figure \ref{fig:sig_sequence} illustrates the sequence of a complete distributed signing process. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_sign_sequence} + \caption{Frosix distributed signing sequence} + \label{fig:sig_sequence} +\end{figure} + +\begin{enumerate} + \item There are always two different inputs needed to start a distributed signing process. Besides a Frosix signing document, the Frosix client needs a challenge-code or the correct answer to a \textit{security question} + for each participating \Gls{provider}. There has to be exactly \textit{threshold-value} numbers of providers! + \item Frosix client starts the first round of the distributed signing process with a request for a random, but message-specific commitment to each participating \Gls{provider} (POST /sig-commitment). + \item After passing the authentication challenge and receiving a commitment from each participating \Gls{provider}, the Frosix client distributes these commitments with the request to each compute a partial signature (POST /sig-share). + \item The Frosix client verifies now each partial signature and aggregates and outputs the final signature. +\end{enumerate} + +\subsubsection{Delete Key} +Figure \ref{fig:del-key_sequence} illustrates the deletion of all private key shares, which belong to a specific public key. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_delete-key_sequence} + \caption{Frosix delete key sequence} + \label{fig:del-key_sequence} +\end{figure} + +\begin{enumerate} + \item To delete the private key shares the signing document has to be provided. + \item The Frosix client then calls for each \Gls{provider} the REST endpoint DELETE /dkg-key with the hash of the encryption key as identifier. + \item A \Gls{provider} deletes a key immediately if there is a corresponding key stored in its database. +\end{enumerate} + +\section{Further Considerations} +Numerous decisions were made throughout the development of Frosix. +Some of them are mentioned and explained below. + +\subsubsection{Data Parsing} +In Frosix, the use of JSON data is employed for input, output and transmission. +The parsing of JSON data is facilitated by the use of Libjannson \cite{libjansson}. +This approach significantly mitigates the risks associated with manual parsing, +as Libjansson is widely adopted and reviewed. + +\subsubsection{POST vs GET} +The majority of the REST endpoints accept only POST requests, although there are some exceptions (see appendix~\ref{appendix_a}). +This design choice is driven by the objective of transmitting all data encrypted (over TLS). +All data must therefore be in the body of the request. +\custind An identifier in every request allows to correlate the request between the rounds of Frosix key generation and Frosix sign. +This identifier is a hash over all relevant data in the body of the request, +therefore it doesn't matter if the identifier gets logged from various systems while being transmitted between the Frosix client and a \Gls{provider}. + +\subsubsection{Denial-of-service} +Since in Frosix's adversary model, an adversary has full control over the user's device and can therefore suppress and manipulate all network communication, +Frosix cannot protect against such denial-of-service (DoS) attacks! +\custind Additionally, Frosix lacks robustness against misbehaving providers, resulting in abortion of the protocol if anything fails. + +\subsubsection{Availability Considerations} +Protection against denial-of-service (DoS) attacks is an important aspect in the design of the \Glspl{provider}. +A good protection against a large number of requests, with the objective of exhausting the \Gls{provider} 's resources, +is to always require a small payment in advance. However, this is currently not implemented (see chapter~\ref{chap:payment}). + +Frosix incorporates an expiration date for all stored data in the database. +The commitments stored during Frosix key generation, which may consume much memory, +are stored for a few minutes only. +Moreover, the key data, which have a long storage time (some years), require only minimal storage space. +This makes it challenging for an adversary to exhaust a provider's storage capacity. + +Furthermore, Frosix employs rate limiting within the database to mitigate exhaustive repeated requests in Frosix Sign. +However, it is important to note that Frosix does not offer protection against other network-based DoS attacks beyond its own scope of operation. + +\section{Performance} +This section lists some performance measurements of Frosix, running single threaded on an Intel Core i7-7600U CPU. +All data points represent a single run of the application as performance is quite predictable and thus multiple runs were not deemed necessary. +Furthermore, the measurements are not completely accurate due to heat-based throttling, but they show the general tendency. + +\newpage +\subsubsection{Frosix key generation} +Figure~\ref{fig:perf_dkg_threshold} shows the linear increase if the \textit{threshold-value} is raised. +\newline This is done with the number of parties fixed to the value 240. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_perf_dkg_threshold} + \caption{Performance of Frosix key generation of a \Gls{provider} depending on the threshold value} + \label{fig:perf_dkg_threshold} +\end{figure} + +Figure~\ref{fig:perf_dkg_parties} shows a second linear increase if the \textit{number of parties} is raised. +In this example the threshold-value is fixed to a value of only 10, resulting in much smaller numbers. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_perf_dkg_parties} + \caption{Performance of Frosix key generation of a \Gls{provider} depending on number of involved \Glspl{provider}} + \label{fig:perf_dkg_parties} +\end{figure} + +Figure~\ref{fig:perf_dkg_combined} shows the behavior if the \textit{threshold-value} is always \textit{number of parties - 1}, +therefore we have a situation of nearly $n = k$. +As the incrementation of both values on its own results in a linear increase, +if both values are incremented at the same time the complexity is squared. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_perf_dkg_combined} + \caption{Performance of Frosix key generation of a \Gls{provider} if k = n} + \label{fig:perf_dkg_combined} +\end{figure} + +\subsubsection{Frosix sign} + +Figure~\ref{fig:perf_sign_provider} shows the time required for a \Gls{provider} to create a partial signature. +Since the sole dependency of signing a message is the \textit{threshold-value}, +the increase is linear. In contrast to Frosix sign, the maximum number needed to sign a message is smaller by a factor of about 20. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_perf_sign_provider} + \caption{Performance of Frosix sign of a \Gls{provider} depending on the threshold value} + \label{fig:perf_sign_provider} +\end{figure} + +Figure~\ref{fig:perf_sign_client} shows the time needed for the Frosix client to verify the partial signatures. +This is quite an inefficient computation in the current implementation, with a complexity of $O(n^2)$. +There is in principle a simple way to reduce the computation cost of this step to almost zero. +However, this was left for future work (see chapter \ref{future_work}). + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_perf_sign_client} + \caption{Performance of Frosix sign of Frosix client depending on the threshold value} + \label{fig:perf_sign_client} +\end{figure} + +\subsubsection{Frosix verify} + +The verification of threshold signatures is very fast and because its always one signature to verify, +has a complexity of \(O(1)\), as Figure~\ref{fig:perf_verify_client} shows. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{frosix_perf_verify_client} + \caption{Performance of Frosix verify of Frosix client depending on the threshold value} + \label{fig:perf_verify_client} +\end{figure} + +\newpage +\section{Testing} +At the moment, there are only two integration tests. + +\subsubsection{Libfrost} +The first integration test is a compiled binary which runs every high level function of libfrost once. + +\begin{itemize} + \item performs a distributed key generation + \item signs a message + \item checks if the resulting signature can be verified +\end{itemize} + +\subsubsection{Frosix} +The integration test of Frosix is a shell script which does the following. + +\begin{itemize} + \item creates and resets (in case they already exist) five instances of PostgreSQL databases + \item starts five \Glspl{provider} with predefined configuration files + \item runs a Frosix key generation among all five \Gls{provider} with a predefined providerlist + and stores the result Frosix in a Frosix signing document + \item runs a Frosix sign with three \Glspl{provider}, using the previously created Frosix signing document + and stores the result in a signature file + \item runs Frosix verify with the signature file and the message which was signed and checks if the verification succeeds. +\end{itemize} diff --git a/doc/bachelor-thesis/content/introduction.tex b/doc/bachelor-thesis/content/introduction.tex @@ -0,0 +1,144 @@ +In today's digital landscape, signatures play a crucial role in nearly every +aspect of modern informatics. Through the use of signatures, we are able to +validate the authenticity, integrity and non-repudiation of any digital information. + +The private signing key is the most crucial component for creating a signature +and must be kept secret at all costs. +But keeping a private key confidential is a challenging task, often underestimated in the past +\cite{heise:msi-hack} \cite{schneier:leaked-keys} \cite{github:stolen-keys} \cite{malwarebytes:nvidia-keys}. + +A popular security solution is the use of a hardware security module (HSM) \cite{IR8320}. +Even though these modules are considered secure, they are quite expensive +and require trust in a single manufacturer. + +Qualified signatures represent the digital signature in a legally valid form \cite{admin:qes}. +In Switzerland, there are currently three providers \cite{bit:qes} which provide qualified signatures +for the general public. Only one of these providers allows to use an HSM for signing, +with the other two providers always creating the signatures under their sovereignty. + +For signing cryptocurrency transactions, multi-signatures are the preferred way to protect a wallet \cite{bitcoin:multisig}. +With multi-signatures, there are several entities, each possessing its own private and public key. +In order to obtain a valid signature, it is required that a certain number of these entities +must provide a signature on its own. +This is inefficient because the size of the resulting signature increases linearly with +the number of signers and the verification becomes more costly, +because the signature of each signer must be verified individually. + +The field of multiparty threshold signature schemes aims to address these three main problems, namely: +\begin{itemize} + \item keeping a private key confidential, + \item avoiding the need to trust in a single provider or a single device, and + \item being efficient in terms of size and verification cost. +\end{itemize} + +The contribution of this work is the implementation of such a threshold signature scheme, +combined with strong authenticated signing. + +Frosix is mainly based on FROST \cite{cryptoeprint:2020/852}, +a promising threshold signature scheme. +Even though FROST proposes an advanced protocol for the distributed creation of signatures, +it lacks any authentication of the central signature aggregator against the signing parties. +Therefore, Frosix extends FROST with an authentication component, inspired by GNU Anastasis +\cite{anastasis}.\footnote{GNU Anastasis is a free software key recovery service and resulted from an earlier bachelor thesis.} + +\section{Principles} +The following design objectives were important during the design and development of Frosix. +Those principles were freely adapted from the Anastasis bachelor thesis. \cite{anastasis-thesis} + +\begin{itemize} + \item Frosix must be Free Software \cite{fsf}. Everyone must + have the right to run the program, study the source code, make modifications + and share their modifications with others. + \item Frosix must not rely on the trustworthiness of individual \Glspl{provider} or devices. + It must be possible to use Frosix safely, even if a subset (\(k - 1\)) of \Glspl{provider} + and devices, respectively their used authentication methods, are malicious. + \newline Furthermore, Frosix must minimize the amount of information exposed to + \Glspl{provider} and the network. + \item Frosix must put the user in control: They get to decide which + \Glspl{provider} and which authentication methods to use. + \item Frosix must be economically viable to operate. This implies usability + and efficiency of the system. + \item Signatures generated with Frosix must support a diverse range of use + cases. +\end{itemize} + +\section{Basics} +\textit{Frosix} is the combination of the word \textit{FROST} and the +abbreviation \textit{six} originating from the word \textit{signature}. + +\subsubsection{Threshold Cryptosystem} +Frosix is based on a threshold cryptosystem with the following basic properties: + +\begin{itemize} + \item \textbf{Distribution of the secret}: In a threshold cryptosystem, the threshold value $k$, or sometimes $t$, states, + how many entities an adversary has to compromise in order to reconstruct a distributed secret. + \item \textbf{Robustness in reconstruction of the secret}: This also implies at the same time that only \(k\) entities have to collaborate in order to reconstruct the secret. +\end{itemize} + +A threshold signature scheme involves the following components, which differ from a single-signer signature or multi-signature scheme. + +\textbf{Distributed Key Generation} +\newline For the generation of a private key, a distributed key generation protocol ensures +that no entity knows more than a fraction of the private key. +\custind Frosix ensures that even the device of the user who initiated the key generation +learns nothing about the private key, except for the public key that is eventually created. + +\textbf{Distributed Signing} +\newline In order to never constitute the private key on a single device, +each entity involved in the signing process generates a partial signature with its fraction of the private key. +\custind A central signature aggregator, the Frosix client, combines those parts to create the final signature. + +\subsubsection{Authentication} +In current threshold signature schemes, the trustworthiness of the issuer of a request is not taken into account for the creation of a signature. +Frosix closes this gap with the offering and enforcing of different authentication methods for each involved \Gls{provider} and each signing request. +This results, depending on the combinations of chosen authentication methods, +in the highest possible security level threshold signing can have. + +\subsubsection{Privacy by Design} +Frosix is designed to minimize the information exposed to the user, the network and to \Glspl{provider}. +Thus, the data persisted at a \Gls{provider} is either encrypted or just a salted hash. +The encryption key and the salt value are only submitted during the key generation or a signing process. + +\section{Use cases} +One of the main advantages of Frosix in comparison to current implementations is the +inclusion of authentication before issuing a signature share. + +\subsubsection{Software Signing} +Modern operating systems rely on signed software as root of trust to +protect users from malicious software. +However, many software development companies do not adequately secure +their software signing keys. +Frosix can significantly enhance security in this context, +and it can also establish trust in software updates and releases from independent +developers to reduce the risk of malicious code being committed to public +registries like GitHub. + +\subsubsection{Document Signing} +Frosix is designed to sign anything that can be processed by a hash function. +This includes documents such as contracts, testaments, +and various media files like pictures, music, and videos. +For contracts and other legally binding documents, Frosix could take on the role of +a qualified signature, provided the legal conditions are met. + +\subsubsection{Cryptocurrency Transactions} +Frosix is particularly well-suited for use in the signing of +cryptocurrency transactions, as the underlying FROST scheme was originally +designed for this purpose. +With the introduction of the Taproot upgrade in Bitcoin \cite{taproot}, +which enables support for Schnorr signatures, Frosix could be customized +to issue valid Bitcoin transaction signatures. + +\subsubsection{E-mail / Communication} +Frosix can also be used for signing written digital communication, such as emails. +However, the requirement for multiple authentications makes Frosix less suitable for everyday +and trivial communications. +Nonetheless, this feature becomes increasingly valuable when considering the +security properties of authenticity, integrity, and non-repudiation +associated with sensitive communications. + +\subsubsection{Financial Industry} +Another field of application for Frosix lays in the financial industry. +Banks and other financial institutions manage immense assets, +and are therefore obliged to comply with the highest IT security standards. +Threshold signatures could serve as a supporting element to distribute +and thus reduce financial and regulatory risks. +\ No newline at end of file diff --git a/doc/bachelor-thesis/content/project_plan.tex b/doc/bachelor-thesis/content/project_plan.tex @@ -0,0 +1,50 @@ +At the beginning of the semester, the objectives of this bachelor-thesis were discussed and defined. +As this is an individual project, and the time available is limited, some objectives were declared as optional. +Following are the parts to be implemented. + +\begin{itemize} + \item a webserver with + \begin{itemize} + \item all necessary REST endpoints + \item the link to libfrost + \item the logic for the authentication + \item a database + \end{itemize} + \item a matching REST client which addresses all REST endpoints from the webserver + \item the main logic of the client (link to libfrost and additional cryptography) + \item a command line interface which exposes the implemented functions + \item the authentication method \textit{security question} + \item an integration test + \item further authentication methods like sms, email, etc. (optional) + \item a graphical user interface (GUI) (optional) + \item the integration of GNU Taler as payment system (optional) +\end{itemize} + +Moreover, there are further objectives like code documentation and the mandatory assignments for a Thesis at the BFH: + +\begin{itemize} + \item the project documentation (thesis) with an adversary model and the discussion about the decisions made + \item a book page + \item a poster for the exhibition + \item a video +\end{itemize} + +Below is the project plan (Figure \ref{fig:project_plan}), as it was originally intended. + +\begin{figure}[H] + \centering + \includegraphics[scale=0.5]{project_planning} + \caption{Frosix project plan} + \label{fig:project_plan} +\end{figure} + +As is often the case, unexpected things can disrupt every plan. In this case, a week, including +two weekends, was lost due to illness. +Consequently, the schedule became difficult to keep, necessitating a more intensive final push in the last weeks. + +Despite investing more time than initially anticipated, it was not possible for me to cover all the optional objectives. +This was partly due to the fact that there were some last-minute changes to be made to Frosix. +Namely, the realization of the danger posed by nonce reuse, if Frosix uses deterministic signing as originally planned and implemented. + +Additionally, the time required to write, revise and complete the thesis, particularly the chapter \textit{related work}, +was highly underestimated. diff --git a/doc/bachelor-thesis/content/related_work.tex b/doc/bachelor-thesis/content/related_work.tex @@ -0,0 +1,436 @@ + +\section{Cryptographic Principles} +In this chapter, all relevant cryptographic principles used in Frosix are explained and described. + +\subsection{Randomness} +"Any one who considers arithmetical methods of producing random digits is, of course, in +a state of sin." \cite{neumann:1951} + +In the field of cryptography, good randomness is crucial \cite[page 3]{vadhan:2012}, +but it is difficult for computers to behave unpredictably. +We therefore need some mechanisms which come close to and are indistinguishable from true random: +computational indistinguishability. \cite[chapter 7.1.1]{vadhan:2012} + +\subsubsection{Pseudo Random Generator} +A pseudo random number generator (PRG or PRNG) algorithm produces a long sequence of +bytes, for which there exist no efficient algorithm to distinguish it from a +true random sequence. Since an algorithm can not produce true random, a PRG +needs to be seeded with a short and perfectly random input. \cite[page 5]{vadhan:2012} + +\textbf{Pseudo Random Function} +\newline To build a pseudo random function (PRF), a PRG can be used. A PRF is a +deterministic function whose output is indistinguishable from true random +and there is no efficient way to gain any information about the input seed, +unless this seed is already known. \cite[page 223]{vadhan:2012} + +\subsubsection{Entropy} +Entropy is the measurement of how much randomness is in a random variable. +The notion is always a log to the base 2. For example, an entropy value of $128$ +means that there are $2^{128}$ possibilities, all of which are equally likely. +This is also called uniform distribution. \cite[chapter 6.1.2]{vadhan:2012} + +\subsection{Hash} +A hash function is technically speaking a compression function and is defined as a +function that takes an input with arbitrary length and returns a fix-sized +output. \cite[chapter 2]{sobti:2012}. +\custind To become useful for cryptography, a hash function must fulfill +following additional properties and is then known as cryptographic hash function \cite[chapter 5]{sobti:2012}: + +\begin{itemize} + \item \textbf{Avalanche Criterion}: A good hash function generates for two different input two completely different outputs, + regardless how small the difference in the inputs are. + This results in the avalanche criterion, where changing one bit in the input, + changes every bit in the output with a probability of 0.5. \cite[chapter 5.2]{sobti:2012} + \item \textbf{Pre-Image Resistance}: A hash function is said to be pre-image resistant if it is difficult to find the input, + if only the output is given. + \newline "Given $H$ and $H(x)$, it is computationally infeasible to find $x$." \cite[chapter 2.1]{sobti:2012} + Such a hash function is also known as One Way Hash Function. + \item \textbf{Second Pre-Image Resistance}: To be second pre-image resistant, it must be difficult to find a second input + for a given input which leads to the same output. + \newline "it is computationally infeasible to find any second input which has + the same output as any specified input, i.e., given $x$, to find a 2nd-preimage $x' = x$ such that + $h(x) = h(x')$." \cite[chapter 3.3]{cryptoeprint:2004/035} + \item \textbf{Collision Resistance}: The strongest property of a cryptographic hash function is its collision resistance. + With a collision resistance hash function, it is hard to find two different inputs which lead to the + same output. + \newline "it is computationally infeasible to find any two distinct inputs $x$, $x'$ which has the same output, i.e., + such that $h(x) = h(x')$." \cite[chapter 9.2.2]{appliedcryptography} +\end{itemize} + +\subsubsection{HMAC} +In network communication, the message authentication code (MAC) is used to verify the integrity and authenticity +of received information. A MAC is a "cryptographic checksum", based on a shared key \cite[chapter 1.1]{bellare:1996}. +\custind The hash-based message authentication code (HMAC) scheme is based on the principle of a MAC and utilizes a cryptographic hash function ($H$), with a key ($k$) and a message ($x$) as input: + +\begin{center} + $HMAC_k(x) = H(\overline{k} \oplus opad, H(\overline{k} \oplus ipad, x))$ \cite[chapter 5.1]{bellare:1996} +\end{center} + +\subsubsection{HKDF} +Goal of a key derivation function (KDF) is to derive "one or more cryptographically strong secret keys" \cite[chapter 1]{cryptoeprint:2010/264} from a probably not +uniformly distributed key. Thus, a KDF contains two phases. In the extraction phase, a pseudorandom key is extracted and in the second phase expanded to +the desired output length, with the help of a pseudo random function (PRF). +\custind In a hashed key derivation function (HKDF), the HMAC scheme is utilized in the extraction phase to get the pseudorandom key as well as +in the expansion phase as PRF. \cite[chapter 4.2]{cryptoeprint:2010/264}. +\custind Frosix makes intensive use of HKDF functions to deterministically expand high entropy inputs (see chapter \ref{chap:rnd}). + +\subsubsection{PBKDF} +A password-based key derivation function (PBKDF) derives a pseudorandom key from a low-entropy password. Unlike a HKDF, a PBKDF scheme uses +an adaptable number of iterations to derive the resulting key, thus making it hard to brute-force the password. \cite[chapter 3]{RFC8018} + +\textbf{Argon2} +\newline Argon2 is a PBKDF which aims to "maximize the cost of password cracking on ASICs" \cite[page 2]{argon2}. +Therefore, Argon2 is designed to not only use many iterations +in order to derive a pseudorandom key from a low-entropy password, but at the same time uses a lot of memory, making it "memory-hard" \cite[page 9]{argon2}. +\custind Frosix uses Argon2 (Argon2id) to derive a seed from the secret answer to make brute forcing as inefficient as possible. + +\subsection{Public Key Cryptography} +"In a public-key cryptographic scheme, a key pair is selected so that the problem of deriving the +private key from the corresponding public key is equivalent to solving a computational problem +that is believed to be intractable." \cite[chapter 1.2]{Hankerson2004GuideTE} +\custind Public key cryptography relies either on the hardness of the factorization problem (RSA), the discrete logarithm problem (DL), +or the elliptic curve discrete logarithm problem (EC). \cite[chapter 1.2]{Hankerson2004GuideTE} + +\subsubsection{Elliptic Curves} +In cryptography, an elliptic curve is built on the finite field $\mathbb{F}_p$, +and is defined by an equation of the form + +\begin{center} + $y^2 = x^3 + ax + b$, where a, b $\in \mathbb{F}_p$ and $4a^3 + 27b^2 \not\equiv 0$ (mod p) \cite[page 13]{Hankerson2004GuideTE}. +\end{center} + +Every pair \((x, y) \in \mathbb{F}_p^2\) is a point on the curve if above equation is satisfied. \cite[page 13]{Hankerson2004GuideTE} +Advantages of elliptic curves are their smaller key size, compared to RSA or DSA, to achieve the same security level. \cite[page 19]{Hankerson2004GuideTE} + +A finite field is the set $\mathbb{F}$, together with the two operations addition and multiplication, and fulfills +specific properties \cite[chapter 2.1]{Hankerson2004GuideTE}: + +\begin{itemize} + \item \((\mathbb{F}, +)\) is an abelian group with (additive) identity denoted by 0. + \item \((\mathbb{F} \setminus \{0\}, \cdot)\) is an abelian group with (multiplicative) identity denoted by 1. + \item The distributive law holds: \((a + b) \cdot c = a \cdot c + b \cdot c\) for all \(a,b,c \in \mathbb{F}\). + \item If the set \(\mathbb{F}\) is finite, then the field is said to be finite. +\end{itemize} + +\textbf{Ristretto255 Group} +\newline The ristretto255 group is an adaption of the Curve25519, "a state-of-the-art elliptic-curve-Diffie-Hellman function +suitable for a wide variety of cryptographic applications" \cite[chapter 1]{10.1007/11745853_14}. +Ristretto is based on a technique called Decaf \cite{cryptoeprint:2015/673} and allows the construction +of prime-order groups from non-prime-order elliptic curves with cofactor 8, such as Curve25519. \cite[chapter 1]{irtf-cfrg-ristretto255-decaf448-07} +\custind As recommended by the authors of FROST, Frosix uses ristretto255 as the underlying prime-order group. \cite[chapter 6]{irtf-cfrg-frost-13} + +\subsubsection{ECDHE} +Elliptic Curve Diffie-Hellman Ephemeral (ECDHE) is a key agreement protocol, which allows a shared key to be established over an +untrusted channel. \cite[chapter 6.1]{secg:sec1-v2} +\custind Frosix uses ECDHE to transmit the secret shares in round 2 and 3 of the key generation protocol. + +\subsubsection{Digital Signature} +A digital signature is a construct "which associates a message (in digital +form) with some originating entity" \cite[chapter 11.2]{appliedcryptography}. +\custind There exists a lot of different signature schemes, but all of them +consist of three basic algorithms: \cite[chapter 11.2.2]{appliedcryptography} +\begin{itemize} + \item \textbf{Key Generation}: In a key generation a key pair has to be created. A key pair consists out of a private key + \(sk\) and a public key \(pk\). The private key is chosen secretly and at random, or at least derived from high entropy. + Afterwards, the public key can be derived from the private key. + \item \textbf{Signature Generation}: With the private key from the previously generated key pair, arbitrary messages can be signed. + \item \textbf{Signature Verification}: Anybody in possession of the public key and the verification function can now + verify, whether a signature matches a message. +\end{itemize} + +\subsubsection{Schnorr Signature Scheme} +The Schnorr signature scheme is an efficient signature scheme, based on discrete logarithms: \cite{crypto-1989-1727} + +\begin{itemize} + \item primes $p$ and $q$ such that $q$ | $p-1$ + \item $\alpha \in \mathbb{Z}_p$ with order $q$, $\alpha^q = 1$ (mod $p$), $\alpha \neq 1$ + \item \textbf{Key Generation}: + \begin{enumerate} + \item Chose private key \(s \in \{1, 2, ..., q\}\). + \item The corresponding public key \(v\) is the number $v = \alpha^{-s}$ (mod $p$). + \end{enumerate} + \item \textbf{Signature Generation}: The key pair $s, v$ and the message $m$ are provided. + \begin{enumerate} + \item Pick a random number \(r \in {1, ..., q}\) and compute \(x := \alpha^r\) (mod $p$). + \item Compute \(e := h(x,m) \in \{0, ..., 2^t-1\}\). + \item Compute \(y := r + se\) (mod q) and output the signature \((e,y)\). + \end{enumerate} + \item \textbf{Signature Verification}: The signature ($e$, $y$) for message $m$ and the public key $v$ are provided. + \begin{enumerate} + \item Compute \(\overline{x} = \alpha^y v^e\) (mod p). + \item Check that \(e = h(\overline{x},m)\). + \end{enumerate} +\end{itemize} + +Due to a patent, which expired in 2008, Schnorr signature schemes were not common for a long time. + +\textbf{EdDSA} +\newline Nowadays, the Edwards-curve Digital Signature Algorithm (EdDSA) \cite{rfc8032}, +a deterministic variant of the Schnorr Signature Scheme +on elliptic Edwards-curve, is standardized and widely used. +\custind Frosix uses EdDSA signatures to let each involved provider sign the resulting public key in the key generation process. + +\subsubsection{Secret Sharing} +\textbf{Shamir's Secret Sharing} +\newline Shamir's secret sharing is a method to divide some data D into n parts, based on polynomial interpolation +and has the following two properties \cite{10.7551/mitpress/12274.003.0048}: + +\begin{enumerate} + \item knowledge of any \(k\) or more \(D_i\) pieces makes \(D\) easily computable + \item knowledge of any \(k - 1\) or fewer \(D_i\) pieces leaves \(D\) completely undetermined (in the sense that all its possible + values are equally likely) +\end{enumerate} + +\textbf{Feldman's Verifiable Secret Sharing} +\newline In Shamir's secret sharing a party can not verify if the received piece is valid. +In Feldman's verifiable secret sharing \cite{10.1109/SFCS.1987.4}, +the \gls{trusted dealer} first publishes a commitment of the secret, with which each receiving party can test, +whether the afterwards sent piece is a valid part of that secret. \cite[chapter 3.2]{10.1109/SFCS.1987.4} + +\subsubsection{Threshold Signature Scheme} +In a threshold signature scheme, the private key is distributed among $n$ parties, such that \(k \leq n\) parties can collaborate to generate +a valid signature. +To achieve a signature system, wherein the signing key is not combined in any single place at any time, it is mandatory to +also generate the key pair with a multiparty algorithm in a distributed key generation process. \cite[chapter 1]{cryptoeprint:2020/1390} + +\subsubsection{Distributed Key Generation} +\textbf{Pedersen's Distributed Key Generation} +\newline In order to perform a key generation among a group, Torben Pedersen introduced a distributed key generation protocol (DKG) \cite{10.1007/3-540-46416-6_47}, +based on verifiable secret sharing. +\custind In Pedersen's distributed key generation, each party performs a verifiable secret sharing, thus acts as a \gls{trusted dealer}. +After publishing all commitments, each party sends to every other party a secret share, like in Shamir's secret sharing. +The final share of the private key is the combinations of a self-generated secret share, combined with the secret shares received from all other parties. +\custind Therefore, two main properties can be concluded \cite[chapter 5]{10.1007/3-540-46416-6_47}: + +\begin{enumerate} + \item A trusted party for selecting and distributing the secret is no longer needed. + \item Each member of the group can verify that his share of the secret key corresponds to the public key. +\end{enumerate} + +\section{FROST Signature Scheme} +FROST is a Flexible Round-Optimized Schnorr Threshold Signature scheme. +It is optimized to be as efficient as possible, without restrictions to the security properties. +Although it can be instantiated as a single-round protocol, with a pre-processing stage, +in Frosix, FROST is instantiated as the two-round protocol variant. +\custind Signatures produced by FROST signing operations are verifiable using the standard Schnorr verification operation +and use a signature format similar to EdDSA. \cite{cryptoeprint:2020/852} + +\subsubsection{FROST Key Generation} +Like many other threshold signature protocols, FROST builds upon Pedersen's DKG for key generation, +but adds a \gls{zero knowledge proof} to protect against rogue key attacks. +The zero knowledge proof is a Schnorr signature on its own, using the secret value from the verifiable secret sharing as private key. +\custind Whereas this key generation protocol is originally designed to be a two-round protocol, +in Frosix, the distributed key generation is a three-round protocol, +due to the tunneling of all communication through the Frosix client. + +Below is the original \textit{FROST KeyGen} \cite[page 12]{cryptoeprint:2020/852}: + +\begin{center} + \textbf{Round 1} +\end{center} + +{\large \(P_i\)} +\par \textbf{Step 1}: Every participant \(P_i\) samples \(t\) random values and uses these values as coefficients to define a degree \(t-1\) polynomial. + +{\small $\displaystyle (a_{i0}, ..., a_{i(t-1)}) \xleftarrow{\$} \mathbb{Z}_q$} \\ +{\small $\displaystyle f_i(x) \ =\ \sum _{j=0} ^{t-1} a_{ij}x^j$} + +\textbf{Step 2}: Every \(P_i\) computes a proof of knowledge to the corresponding secret \(a_{i0}\). + +{\small $\displaystyle k \xleftarrow{\$} \mathbb{Z}_q$} \\ +{\small $\displaystyle R_i \ =\ g^k$} \\ +{\small $\displaystyle c_i \ =\ H(i, \$context\_string, g^{a_{i0}}, R_i)$} \\ +{\small $\displaystyle z_i \ =\ k + a_{i0} \cdot c_i$} \\ +{\small $\displaystyle \sigma_i \ =\ (R_i, z_i)$} + +\textbf{Step 3}: Every participant \(P_i\) computes a public commitment \(C\). + +{\small $\displaystyle \phi_{ij} \ =\ g^{ij}, 0 \leq j \leq t-1$} \\ +{\small $\displaystyle \vec{C_i} \ =\ \langle \phi_{i0}, ..., \phi_{i(t-1)} \rangle$} + +\textbf{Step 4}: Every \(P_i\) broadcasts \(C_i, \sigma_i\) to all other participants. + +\begin{center} + {\small $\displaystyle (C_i, \sigma_i) \longrightarrow $} +\end{center} + +\textbf{Step 5}: Upon receiving \(C_l, \sigma_l\) from participants \(1 \leq l \leq n, l \neq i\), each participant \(P_i\) verifies \(\sigma_l\). + +{\small $\displaystyle c_l \ =\ H(l, \$context\_string, \phi_{l0}, R_l)$} \\ +{\small $\displaystyle R_l \overset{?}{=} g^{z_l} \ \cdot \phi_{l0}^{-c_l}$} + +\begin{center} + \textbf{Round 2} +\end{center} + +{\large \(P_i\)} +\par \textbf{Step 1}: Each \(P_i\) securely sends a secret share ($l, f_i(l)$) to each other participant $P_l$. + +\begin{center} + {\small $\displaystyle (l, f_i(l)) \longrightarrow$} +\end{center} + +\textbf{Step 2}: Each \(P_i\) verifies their received shares. + +{\small $\displaystyle g^{f_l(i)} \ \overset{?}{=} \ \prod _{k=0} ^{t-1} \phi_{lk}^{i^k mod \ q}$} + +\textbf{Step 3}: Each \(P_i\) calculates their long-lived private signing share \(s_i\). + +{\small $\displaystyle s_i \ =\ \sum _{l=1} ^n f_l(i)$} + +\textbf{Step 4}: Each \(P_i\) calculates their public verification share \(Y_i\) and the group's public key \(Y\). + +{\small $\displaystyle Y_i \ =\ g^{s_i}$} \\ +{\small $\displaystyle Y \ =\ \prod _{j=1} ^n \phi_{j0}$} + +\subsubsection{FROST Sign} +Since Frosix uses the two-round variant of FROST Sign, +round 1 represents a single preprocess operation. +Otherwise, the protocol below is as unmodified as possible. \cite[page 12, 15]{cryptoeprint:2020/852} + +\begin{center} + \textbf{Round 1} +\end{center} + +{\large $SA$} \hfill {\large $\displaystyle P_{i}{}_{\in}{}_{S}$} +\par \textbf{Step 1}: In the first round of FROST Sign, the signature aggregator (SA) chooses the set $S$, $k$ of $n$ parties. + +{\small $\displaystyle S = \{P_1,...,P_k\}, 0 < P_i \leq n$} + +\textbf{Step 2}: Each party (\(P_i\)) samples two random commitment values and sends those to the SA. + +\begin{flushright} + {\small $\displaystyle (d_i,e_i) \xleftarrow{\$} \mathbb{Z}^*_q \times \mathbb{Z}^*_q$} \\ + {\small $\displaystyle (D_i,E_i) \ = \ (g^{d_i},g^{e_i})$} +\end{flushright} + +\begin{center} + {\small $\displaystyle \longleftarrow (D_i,E_i)$} +\end{center} + +\begin{center} + \textbf{Round 2} +\end{center} + +{\large $SA$} \hfill {\large $\displaystyle P_{i}{}_{\in}{}_{S}$} + +\textbf{Step 1}: The SA fetches all commitments, builds the set $B \ = \ \langle i,D_i,E_i \rangle, i \in S$ and sends $B$ together with the message $m$ to all parties in $S$. + +{\small $\displaystyle B \ =\ \langle ( i,D_{i} ,E_{i})\rangle _{i}{}_{\in }{}_{S}$} + +\begin{center} + {\small $\displaystyle ( m,\ B) \longrightarrow $} +\end{center} + +\textbf{Step 2}: After receiving $(m,\ B)$, each $P_i$ validates the message $m$, and then checks $D_l,E_l \in \mathbb{G}^*$ for each commitment in $B$, aborting if either check fails. + +\textbf{Step 3}: Each $P_i$ then computes the set of binding values. + +\begin{flushright} + {\small $\displaystyle p_l \ = \ H_1(l,m,B), l \in S$} +\end{flushright} + +\textbf{Step 4}: Each $P_i$ then derives the group commitment $R$ and the challenge $c$. + +\begin{flushright} + {\small $\displaystyle R \ =\ \prod _{l \in S} D_l \cdot (E_l)^{\rho_l}$} \\ + {\small $\displaystyle c \ =\ H_2(R,Y,m)$} +\end{flushright} + +\textbf{Step 5}: Each $P_i$ computes their response $z_i$ using their long-lived secret share $s_i$. + +\begin{flushright} + {\small $\displaystyle z_i \ =\ d_i + (e_i \cdot \rho_i) + \lambda_i \cdot s_i \cdot c$} +\end{flushright} + +\textbf{Step 6}: Each $P_i$ securely deletes $(d_i,e_i)$ from their local storage, and then returns $z_i$ to SA. + +\begin{center} + {\small $\displaystyle \longleftarrow z_i$} +\end{center} + +\textbf{Step 7}: The signature aggregator SA calculates the set of binding values \(p_l\), +the set of individual commitments \(R_l\), the group commitment \(R\) and the challenge \(c\). +With these values, the SA verifies the validity of each response \(z_i\). + +{\small $\displaystyle p_l \ =\ H_1(l,m,B), l \in S$} \\ +{\small $\displaystyle R_l \ =\ D_l \cdot (E_l)^{\rho_l}, l \in S$} + +{\small $\displaystyle R \ =\ \prod _{l \in S} R_l$} \\ +{\small $\displaystyle c \ =\ H_2(R,Y,m)$} + +{\small $\displaystyle g^{z_i} \overset{?}{=} R_i \cdot Y_i^{c \cdot \lambda_i}$} + +\textbf{Step 8}: The signature aggregator SA computes the resulting signature. + +{\small $\displaystyle z = \sum z_i$} \\ +{\small $\displaystyle \sigma \ =\ (R, z)$} + +\newpage +\section{Authentication} +Authentication makes up a big part of Frosix. +Fortunately, Frosix can build upon the know-how and implementation of GNU Anastasis. +At the moment, GNU Anastasis supports the following authentication methods: \cite{anastasis} + +\begin{itemize} + \item Security Question + \item SMS + \item Email + \item Post + \item Bank Transfer + \item TOTP (Time-based one-time password) +\end{itemize} + +\section{Other Implementations} +Frosix is not the first to implement the FROST signature scheme. +But Frosix is one of the first FROST based application implementing a REST API, +and probably unique, considering the integration of additional authentication. + +Besides the reference implementation \cite{ckomlo:frost}, which provides a simple Rust based library, there are some further libraries available on GitHub. +Most of them are written in Rust or Go and therefore unsuitable to be used in Frosix. +\newline The following list is not exhaustive. + +\begin{itemize} + \item \textbf{Zcash Foundation} \cite{zcash:frost}: Rust based library which provides a high level API to work with various ciphers + \item \textbf{Coinbase} \cite{coinbase:frost}: Go based library, which has been archived and is no longer supported from the authors + \item \textbf{Taurus} \cite{taurusgroup:frost}: Go based library with focus on compatibility on Ed25519 (EdDSA), is not under active development for two years + \item \textbf{Isis Agora Lovecruft} \cite{lovecruft:frost}: Rust based library which is not under development for two years + \item \textbf{Cloudflare} \cite{cloudflare:frost}: a feature request for the Cloudflare Interoperable Reusable Cryptographic Library (CIRCL), written in GO + \item \textbf{Trust-Machines} \cite{trust-machines:frost}: a library which provides an implementation of the original FROST as well as an implementation of Weighted Threshold FROST (see chapter~\ref{chap:future_dev}) in Rust +\end{itemize} + +\section{Future Development}\label{chap:future_dev} +There is ongoing research, and standardization efforts on FROST and threshold signature schemes in general. + +\textbf{FROST as an Internet Draft} +\newline At the moment, FROST is an "Active Internet Draft" at the Internet Engineering Task Force (IETF). \cite{irtf-cfrg-frost-13} +This helped a lot during the implementation of FROST, +because it provides pseudocode for all necessary functions. + +\textbf{NIST First Call for Multi-Party Threshold Schemes} +\newline Also NIST is highly interested in standardizing threshold crypto system, among others for signing. \cite{Peralta_Brandão_2023} + +\textbf{Weighted Threshold FROST: WTF} +\newline The idea of weighted threshold FROST is to optimize the required bandwidth when FROST parties control multiple +keys. \cite{weighted-frost} + +\textbf{Threshold Schnorr with Stateless Deterministic Signing} +\newline In contrast to some single-signer signature schemes, like for example EdDSA, it is not trivial to implement +deterministic signatures in a threshold environment. +This is due to the danger of nonce reuse. \cite{10.5555/648120.747057} +Although there are already first approaches \cite{cryptoeprint:2021/1055}, the implementation of a stateless +deterministic threshold signing should be carefully considered. + +\textbf{FROST2} +\newline There is already an optimized version of FROST, FROST2. \cite{cryptoeprint:2021/1375} +With FROST2, the number of exponentiation required for signing and verification are reduced from linear to constant in the number of signers. + +\textbf{FROST3} +\newline Another paper proposes FROST3, RObust Asynchronous Threshold signatures (ROAST). +ROAST is a wrapper protocol and can be instantiated with FROST. +The authors claim to "obtain the first (nontrivial) asynchronous Schnorr threshold signature protocol" +and that ROAST is also the "first robust protocol that can be setup to guarantee unforgeability against a +dishonest majority ($t-1 \geq n/2$)" \cite{10.1145/3548606.3560583}. +\custind What this means exactly and whether Frosix could benefit from ROAST was not further investigated. + +The further development of FROST and its variants remains exciting! diff --git a/doc/bachelor-thesis/figures/.gitkeep b/doc/bachelor-thesis/figures/.gitkeep diff --git a/doc/bachelor-thesis/figures/DKG-Combined.svg b/doc/bachelor-thesis/figures/DKG-Combined.svg @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="160mm" height="90mm" viewBox="0 0 16000 9000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" stroke-width="28.222" stroke-linejoin="round" xml:space="preserve"> + <path fill="rgb(255,255,255)" stroke="none" d="M 7986,8992 L -13,8992 -13,-13 15984,-13 15984,8992 7986,8992 Z"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 8847,6401 L 2309,6401 2309,1461 15385,1461 15385,6401 8847,6401 Z"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,6400 L 2309,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,5411 L 2309,5411"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,4424 L 2309,4424"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,3436 L 2309,3436"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,2448 L 2309,2448"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,1460 L 2309,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2309,6550 L 2309,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2309,6550 L 2309,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 4924,6550 L 4924,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 4924,6550 L 4924,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 7539,6550 L 7539,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 7539,6550 L 7539,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 10154,6550 L 10154,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 10154,6550 L 10154,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 12769,6550 L 12769,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 12769,6550 L 12769,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,6550 L 15385,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,6550 L 15385,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2309,6400 L 15385,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,6400 L 2309,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,6400 L 2309,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,5411 L 2309,5411"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,5411 L 2309,5411"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,4424 L 2309,4424"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,4424 L 2309,4424"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,3436 L 2309,3436"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,3436 L 2309,3436"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,2448 L 2309,2448"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,2448 L 2309,2448"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,1460 L 2309,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,1460 L 2309,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2309,6400 L 2309,1460"/> + <path fill="none" stroke="rgb(0,69,134)" stroke-width="80" stroke-linejoin="round" d="M 2309,6222 L 2439,6207 2570,6192 2701,6177 2832,6162 2962,6146 3093,6131 3224,6115 3355,6099 3485,6082 3616,6065 3747,6047 3878,6029 4009,6010 4139,5990 4270,5970 4401,5949 4532,5927 4662,5904 4793,5881 4924,5856 5055,5830 5185,5804 5316,5776 5447,5747 5578,5717 5709,5687 5839,5655 5970,5623 6101,5589 6232,5555 6362,5520 6493,5483 6624,5446 6755,5409 6885,5370 7016,5330 7147,5290 7278,5249 7409,5207 7539,5164 7670,5121 7801,5077 7932,5032 8061,4986 8192,4940 8323,4893 8454,4845 8584,4797 8715,4748 8846,4698 8977,4647 9108,4596 9238,4545 9369,4492 9500,4440 9631,4387 9761,4333 9892,4278 10023,4223 10154,4167 10284,4111 10415,4054 10546,3997 10677,3939 10808,3880 10938,3822 11069,3763 11200,3703 11331,3643 11461,3583 11592,3523 11723,3462 11854,3401 11984,3340 12115,3279 12246,3218 12377,3156 12508,3095 12638,3033 12769,2971 12900,2910 13031,2848 13161,2786 13292,2725 13423,2663 13554,2601 13684,2539 13815,2478 13946,2416 14077,2354 14208,2292 14338,2231 14469,2169 14600,2107 14731,2045 14861,1983 14992,1922 15123,1860 15254,1798 15385,1736"/> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="2124" y="6968"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">40</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="4739" y="6968"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">80</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="7261" y="6968"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">120</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="9877" y="6968"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">160</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="12492" y="6968"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">200</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="15108" y="6968"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">240</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1874" y="6521"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">0</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="5532"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">1000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="4544"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">2000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="3556"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">3000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="2568"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">4000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="1580"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">5000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="5036" y="838"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Frosix Service Provider: DKG</tspan></tspan></tspan></text> + <path fill="none" stroke="rgb(0,69,134)" stroke-width="80" stroke-linejoin="round" d="M 5974,8691 L 6774,8691"/> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="6874" y="8811"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre"> </tspan><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Parties = Threshold</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="318px" font-weight="400"><tspan class="TextPosition" x="7763" y="7615"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Threshold</tspan></tspan></tspan></text> + <text class="SVGTextShape" transform="rotate(-90 824 4869)"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="318px" font-weight="400"><tspan class="TextPosition" x="824" y="4869"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Time (ms)</tspan></tspan></tspan></text> +</svg> +\ No newline at end of file diff --git a/doc/bachelor-thesis/figures/DKG-Parties.svg b/doc/bachelor-thesis/figures/DKG-Parties.svg @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="160mm" height="90mm" viewBox="0 0 16000 9000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" stroke-width="28.222" stroke-linejoin="round" xml:space="preserve"> + <path fill="rgb(255,255,255)" stroke="none" d="M 7986,8992 L -13,8992 -13,-13 15984,-13 15984,8992 7986,8992 Z"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 8754,6401 L 2124,6401 2124,1462 15385,1462 15385,6401 8754,6401 Z"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,6400 L 2124,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,5576 L 2124,5576"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,4753 L 2124,4753"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,3930 L 2124,3930"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,3107 L 2124,3107"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,2284 L 2124,2284"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,1460 L 2124,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2124,6550 L 2124,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2124,6550 L 2124,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 4776,6550 L 4776,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 4776,6550 L 4776,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 7428,6550 L 7428,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 7428,6550 L 7428,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 10080,6550 L 10080,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 10080,6550 L 10080,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 12732,6550 L 12732,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 12732,6550 L 12732,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,6550 L 15385,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,6550 L 15385,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2124,6400 L 15385,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1974,6400 L 2124,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1974,6400 L 2124,6400"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1974,5576 L 2124,5576"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1974,5576 L 2124,5576"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1974,4753 L 2124,4753"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1974,4753 L 2124,4753"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1974,3930 L 2124,3930"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1974,3930 L 2124,3930"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1974,3107 L 2124,3107"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1974,3107 L 2124,3107"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1974,2284 L 2124,2284"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1974,2284 L 2124,2284"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1974,1460 L 2124,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1974,1460 L 2124,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2124,6400 L 2124,1460"/> + <path fill="none" stroke="rgb(0,69,134)" stroke-width="80" stroke-linejoin="round" d="M 2124,6317 L 2256,6273 2389,6228 2521,6184 2654,6139 2787,6094 2919,6050 3052,6005 3184,5960 3317,5915 3450,5870 3582,5825 3715,5780 3848,5734 3980,5689 4113,5643 4245,5597 4378,5551 4511,5505 4643,5458 4776,5412 4909,5365 5041,5317 5174,5270 5306,5223 5439,5175 5572,5127 5704,5078 5837,5030 5969,4981 6102,4932 6235,4882 6367,4832 6500,4782 6633,4732 6765,4681 6898,4630 7030,4579 7163,4528 7296,4477 7428,4425 7561,4372 7694,4319 7826,4266 7959,4213 8090,4160 8223,4108 8356,4055 8488,4003 8621,3951 8754,3900 8886,3849 9019,3799 9151,3750 9284,3702 9417,3654 9549,3608 9682,3563 9814,3520 9947,3477 10080,3436 10212,3397 10345,3359 10478,3323 10610,3288 10743,3253 10875,3220 11008,3187 11141,3155 11273,3124 11406,3093 11539,3062 11671,3032 11804,3001 11936,2971 12069,2940 12202,2909 12334,2877 12467,2845 12599,2812 12732,2778 12865,2743 12997,2707 13130,2670 13263,2633 13395,2594 13528,2555 13660,2515 13793,2474 13926,2433 14058,2391 14191,2349 14324,2306 14456,2263 14589,2220 14721,2176 14854,2132 14987,2088 15119,2044 15252,1999 15385,1954"/> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1939" y="6968"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">40</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="4591" y="6968"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">80</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="7150" y="6968"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">120</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="9803" y="6968"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">160</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="12455" y="6968"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">200</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="15108" y="6968"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">240</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1504" y="6521"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">50</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="5697"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">100</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="4874"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">150</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="4050"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">200</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="3227"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">250</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="2404"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">300</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="1580"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">350</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="5036" y="838"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Frosix Service Provider: DKG</tspan></tspan></tspan></text> + <path fill="none" stroke="rgb(0,69,134)" stroke-width="80" stroke-linejoin="round" d="M 6490,8691 L 7290,8691"/> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="7390" y="8811"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Threshold: 10</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="318px" font-weight="400"><tspan class="TextPosition" x="7988" y="7615"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Parties</tspan></tspan></tspan></text> + <text class="SVGTextShape" transform="rotate(-90 824 4869)"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="318px" font-weight="400"><tspan class="TextPosition" x="824" y="4869"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Time (ms)</tspan></tspan></tspan></text> +</svg> +\ No newline at end of file diff --git a/doc/bachelor-thesis/figures/DKG-Threshold.svg b/doc/bachelor-thesis/figures/DKG-Threshold.svg @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="160mm" height="90mm" viewBox="0 0 16000 9000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" stroke-width="28.222" stroke-linejoin="round" xml:space="preserve"> + <path fill="rgb(255,255,255)" stroke="none" d="M 7987,8986 L -13,8986 -13,-13 15986,-13 15986,8986 7987,8986 Z"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 8848,6395 L 2310,6395 2310,1461 15386,1461 15386,6395 8848,6395 Z"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,6394 L 2310,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,5407 L 2310,5407"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,4421 L 2310,4421"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,3434 L 2310,3434"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,2447 L 2310,2447"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,1460 L 2310,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2310,6544 L 2310,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2310,6544 L 2310,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 4489,6544 L 4489,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 4489,6544 L 4489,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 6669,6544 L 6669,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 6669,6544 L 6669,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 8847,6544 L 8847,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 8847,6544 L 8847,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 11027,6544 L 11027,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 11027,6544 L 11027,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 13206,6544 L 13206,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 13206,6544 L 13206,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,6544 L 15386,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,6544 L 15386,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2310,6394 L 15386,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2160,6394 L 2310,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2160,6394 L 2310,6394"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2160,5407 L 2310,5407"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2160,5407 L 2310,5407"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2160,4421 L 2310,4421"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2160,4421 L 2310,4421"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2160,3434 L 2310,3434"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2160,3434 L 2310,3434"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2160,2447 L 2310,2447"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2160,2447 L 2310,2447"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2160,1460 L 2310,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2160,1460 L 2310,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2310,6394 L 2310,1460"/> + <path fill="none" stroke="rgb(0,69,134)" stroke-width="80" stroke-linejoin="round" d="M 2310,6329 L 2418,6286 2527,6244 2636,6201 2745,6158 2854,6115 2963,6073 3072,6030 3181,5988 3290,5945 3399,5903 3508,5861 3617,5820 3726,5778 3835,5737 3944,5696 4053,5655 4162,5615 4271,5575 4380,5535 4489,5495 4598,5456 4707,5417 4816,5379 4925,5341 5034,5303 5143,5265 5252,5228 5361,5190 5470,5153 5579,5116 5688,5079 5797,5042 5906,5005 6015,4968 6124,4931 6233,4894 6342,4857 6451,4820 6560,4783 6669,4745 6777,4708 6886,4670 6995,4632 7104,4593 7213,4555 7322,4517 7431,4479 7540,4440 7649,4401 7758,4362 7867,4323 7976,4284 8084,4244 8193,4205 8302,4165 8411,4126 8520,4086 8629,4046 8738,4006 8847,3966 8956,3927 9065,3887 9174,3847 9283,3807 9392,3767 9501,3727 9610,3687 9719,3647 9828,3607 9937,3568 10046,3528 10155,3488 10264,3449 10373,3410 10482,3370 10591,3331 10700,3292 10809,3254 10918,3215 11027,3177 11135,3139 11244,3101 11353,3063 11462,3025 11571,2987 11680,2950 11789,2912 11898,2874 12007,2836 12116,2798 12225,2760 12334,2721 12443,2682 12552,2643 12661,2603 12770,2563 12879,2522 12988,2481 13097,2439 13206,2397 13315,2354 13424,2311 13533,2267 13642,2222 13751,2177 13860,2131 13969,2085 14078,2039 14187,1992 14296,1944 14405,1897 14514,1849 14623,1801 14732,1753 14841,1704 14950,1655 15059,1606 15168,1558 15277,1509 15386,1460"/> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="2217" y="6962"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">3</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="4304" y="6962"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">40</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="6484" y="6962"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">80</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="8570" y="6962"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">120</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="10750" y="6962"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">160</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="12929" y="6962"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">200</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="15109" y="6962"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">240</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1875" y="6515"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">0</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1319" y="5528"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">1000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1319" y="4541"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">2000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1319" y="3554"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">3000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1319" y="2567"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">4000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1319" y="1580"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">5000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="5037" y="838"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Frosix Service Provider: DKG</tspan></tspan></tspan></text> + <path fill="none" stroke="rgb(0,69,134)" stroke-width="80" stroke-linejoin="round" d="M 7112,8685 L 7912,8685"/> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="8011" y="8805"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Parties: 254</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="318px" font-weight="400"><tspan class="TextPosition" x="7764" y="7609"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Threshold</tspan></tspan></tspan></text> + <text class="SVGTextShape" transform="rotate(-90 824 4866)"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="318px" font-weight="400"><tspan class="TextPosition" x="824" y="4866"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Time (ms)</tspan></tspan></tspan></text> +</svg> +\ No newline at end of file diff --git a/doc/bachelor-thesis/figures/Frosix_JoelUrech.pdf b/doc/bachelor-thesis/figures/Frosix_JoelUrech.pdf Binary files differ. diff --git a/doc/bachelor-thesis/figures/Sign-Client.svg b/doc/bachelor-thesis/figures/Sign-Client.svg @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="160mm" height="90mm" viewBox="0 0 16000 9000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" stroke-width="28.222" stroke-linejoin="round" xml:space="preserve"> + <path fill="rgb(255,255,255)" stroke="none" d="M 7986,8992 L -13,8992 -13,-13 15984,-13 15984,8992 7986,8992 Z"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 8847,7184 L 2309,7184 2309,1461 15385,1461 15385,7184 8847,7184 Z"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,7183 L 2309,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,6365 L 2309,6365"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,5547 L 2309,5547"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,4729 L 2309,4729"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,3913 L 2309,3913"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,3095 L 2309,3095"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,2277 L 2309,2277"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,1460 L 2309,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2309,7333 L 2309,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2309,7333 L 2309,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 3398,7333 L 3398,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 3398,7333 L 3398,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 4488,7333 L 4488,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 4488,7333 L 4488,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 5578,7333 L 5578,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 5578,7333 L 5578,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 6668,7333 L 6668,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 6668,7333 L 6668,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 7757,7333 L 7757,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 7757,7333 L 7757,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 8846,7333 L 8846,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 8846,7333 L 8846,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 9936,7333 L 9936,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 9936,7333 L 9936,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 11026,7333 L 11026,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 11026,7333 L 11026,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 12115,7333 L 12115,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 12115,7333 L 12115,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 13205,7333 L 13205,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 13205,7333 L 13205,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 14295,7333 L 14295,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 14295,7333 L 14295,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,7333 L 15385,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15385,7333 L 15385,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2309,7183 L 15385,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,7183 L 2309,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,7183 L 2309,7183"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,6365 L 2309,6365"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,6365 L 2309,6365"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,5547 L 2309,5547"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,5547 L 2309,5547"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,4729 L 2309,4729"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,4729 L 2309,4729"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,3913 L 2309,3913"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,3913 L 2309,3913"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,3095 L 2309,3095"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,3095 L 2309,3095"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,2277 L 2309,2277"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,2277 L 2309,2277"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,1460 L 2309,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2159,1460 L 2309,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2309,7183 L 2309,1460"/> + <path fill="none" stroke="rgb(0,69,134)" stroke-width="80" stroke-linejoin="round" d="M 2309,7181 L 2363,7180 2417,7180 2472,7179 2526,7178 2581,7177 2635,7176 2690,7175 2744,7174 2799,7173 2853,7171 2908,7170 2962,7169 3017,7167 3071,7165 3126,7163 3180,7162 3235,7159 3289,7157 3344,7155 3398,7152 3453,7149 3507,7147 3562,7143 3616,7140 3671,7137 3725,7133 3780,7129 3834,7125 3889,7121 3943,7117 3998,7113 4052,7108 4107,7103 4161,7098 4216,7093 4270,7088 4325,7083 4379,7078 4434,7072 4488,7066 4542,7061 4597,7055 4651,7049 4706,7042 4760,7036 4815,7030 4869,7023 4924,7017 4978,7010 5033,7003 5087,6996 5142,6988 5196,6981 5251,6973 5305,6966 5360,6958 5414,6950 5469,6942 5523,6933 5578,6925 5632,6916 5687,6908 5741,6899 5796,6890 5850,6880 5905,6871 5959,6861 6014,6852 6068,6842 6123,6832 6177,6822 6232,6812 6286,6802 6341,6792 6395,6782 6450,6771 6504,6761 6559,6750 6613,6739 6668,6729 6722,6718 6776,6707 6831,6696 6885,6685 6940,6674 6994,6662 7049,6651 7103,6639 7158,6627 7212,6614 7267,6602 7321,6589 7376,6575 7430,6562 7485,6548 7539,6533 7594,6518 7648,6503 7703,6487 7757,6471 7812,6454 7866,6437 7921,6419 7975,6401 8029,6383 8083,6364 8138,6346 8192,6327 8247,6307 8301,6288 8356,6269 8410,6250 8465,6231 8519,6212 8574,6193 8628,6174 8683,6156 8737,6138 8792,6120 8846,6103 8900,6086 8955,6070 9009,6054 9064,6038 9118,6023 9173,6008 9227,5993 9282,5978 9336,5963 9391,5949 9445,5934 9500,5919 9554,5904 9609,5889 9663,5874 9718,5858 9772,5842 9827,5826 9881,5809 9936,5792 9990,5775 10045,5757 10099,5738 10154,5719 10208,5700 10263,5680 10317,5660 10372,5640 10426,5619 10481,5598 10535,5577 10590,5556 10644,5535 10699,5513 10753,5492 10808,5470 10862,5448 10917,5427 10971,5405 11026,5384 11080,5362 11134,5341 11189,5319 11243,5298 11298,5276 11352,5254 11407,5232 11461,5210 11516,5187 11570,5164 11625,5140 11679,5117 11734,5092 11788,5067 11843,5041 11897,5015 11952,4988 12006,4960 12061,4931 12115,4901 12170,4870 12224,4839 12279,4806 12333,4772 12388,4738 12442,4702 12497,4666 12551,4628 12606,4589 12660,4549 12715,4509 12769,4468 12824,4425 12878,4381 12933,4335 12987,4289 13042,4242 13096,4193 13151,4143 13205,4093 13259,4041 13314,3987 13368,3933 13423,3878 13477,3822 13532,3766 13586,3708 13641,3650 13695,3591 13750,3532 13804,3473 13859,3413 13913,3353 13968,3293 14022,3232 14077,3172 14131,3111 14186,3051 14240,2991 14295,2931 14349,2872 14404,2813 14458,2754 14513,2696 14567,2637 14622,2580 14676,2522 14731,2464 14785,2407 14840,2350 14894,2293 14949,2237 15003,2180 15058,2124 15112,2067 15167,2011 15221,1955 15276,1899 15330,1843 15385,1787"/> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="2216" y="7751"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">3</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="3213" y="7751"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">20</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="4303" y="7751"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">40</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="5393" y="7751"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">60</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="6483" y="7751"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">80</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="7479" y="7751"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">100</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="8569" y="7751"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">120</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="9659" y="7751"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">140</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="10749" y="7751"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">160</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="11838" y="7751"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">180</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="12928" y="7751"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">200</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="14018" y="7751"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">220</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="15108" y="7751"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">240</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1874" y="7304"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">0</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="6486"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">1000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="5668"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">2000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="4850"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">3000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="4033"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">4000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="3215"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">5000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="2397"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">6000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1318" y="1580"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">7000</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="4242" y="838"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Frosix Client: Verify Signature Shares</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="318px" font-weight="400"><tspan class="TextPosition" x="7763" y="8398"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Threshold</tspan></tspan></tspan></text> + <text class="SVGTextShape" transform="rotate(-90 824 5261)"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="318px" font-weight="400"><tspan class="TextPosition" x="824" y="5261"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Time (ms)</tspan></tspan></tspan></text> +</svg> +\ No newline at end of file diff --git a/doc/bachelor-thesis/figures/Sign-Provider.svg b/doc/bachelor-thesis/figures/Sign-Provider.svg @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="160mm" height="90mm" viewBox="0 0 16000 9000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" stroke-width="28.222" stroke-linejoin="round" xml:space="preserve"> + <path fill="rgb(255,255,255)" stroke="none" d="M 7987,8986 L -13,8986 -13,-13 15986,-13 15986,8986 7987,8986 Z"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 8662,7178 L 1939,7178 1939,1461 15386,1461 15386,7178 8662,7178 Z"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,7177 L 1939,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,6033 L 1939,6033"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,4889 L 1939,4889"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,3747 L 1939,3747"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,2603 L 1939,2603"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,1460 L 1939,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1939,7327 L 1939,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1939,7327 L 1939,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 4180,7327 L 4180,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 4180,7327 L 4180,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 6421,7327 L 6421,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 6421,7327 L 6421,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 8662,7327 L 8662,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 8662,7327 L 8662,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 10903,7327 L 10903,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 10903,7327 L 10903,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 13144,7327 L 13144,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 13144,7327 L 13144,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,7327 L 15386,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,7327 L 15386,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1939,7177 L 15386,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1789,7177 L 1939,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1789,7177 L 1939,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1789,6033 L 1939,6033"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1789,6033 L 1939,6033"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1789,4889 L 1939,4889"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1789,4889 L 1939,4889"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1789,3747 L 1939,3747"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1789,3747 L 1939,3747"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1789,2603 L 1939,2603"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1789,2603 L 1939,2603"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1789,1460 L 1939,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1789,1460 L 1939,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 1939,7177 L 1939,1460"/> + <path fill="none" stroke="rgb(0,69,134)" stroke-width="80" stroke-linejoin="round" d="M 1939,6833 L 2051,6804 2163,6775 2275,6745 2387,6715 2499,6685 2611,6655 2723,6624 2835,6593 2947,6561 3059,6528 3171,6494 3283,6460 3395,6425 3507,6389 3620,6352 3732,6313 3844,6274 3956,6233 4068,6191 4180,6147 4292,6102 4404,6056 4516,6008 4628,5959 4740,5909 4852,5859 4964,5807 5076,5755 5188,5702 5301,5649 5413,5595 5525,5541 5637,5487 5749,5434 5861,5380 5973,5327 6085,5274 6197,5221 6309,5169 6421,5118 6533,5068 6645,5018 6757,4969 6869,4921 6982,4874 7094,4827 7206,4781 7318,4735 7430,4690 7542,4645 7654,4600 7766,4556 7878,4511 7989,4468 8101,4424 8213,4381 8325,4337 8437,4293 8549,4248 8662,4204 8774,4160 8886,4115 8998,4070 9110,4025 9222,3980 9334,3934 9446,3888 9558,3843 9670,3797 9782,3751 9894,3705 10006,3659 10118,3613 10230,3566 10343,3520 10455,3474 10567,3428 10679,3382 10791,3335 10903,3289 11015,3243 11127,3197 11239,3151 11351,3105 11463,3059 11575,3014 11687,2968 11799,2922 11911,2876 12024,2831 12136,2785 12248,2739 12360,2694 12472,2648 12584,2602 12696,2557 12808,2511 12920,2466 13032,2420 13144,2374 13256,2329 13368,2283 13480,2237 13592,2192 13705,2146 13817,2100 13929,2055 14041,2009 14153,1963 14265,1917 14377,1872 14489,1826 14601,1780 14713,1734 14825,1688 14937,1643 15049,1597 15161,1551 15273,1505 15386,1460"/> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1846" y="7745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">3</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="3995" y="7745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">40</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="6236" y="7745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">80</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="8385" y="7745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">120</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="10626" y="7745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">160</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="12867" y="7745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">200</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="15109" y="7745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">240</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1504" y="7298"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">0</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1504" y="6154"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">5</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1319" y="5010"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">10</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1319" y="3867"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">15</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1319" y="2723"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">20</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1319" y="1580"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">25</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="5076" y="838"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Frosix Service Provider: Sign</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="318px" font-weight="400"><tspan class="TextPosition" x="7764" y="8392"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Threshold</tspan></tspan></tspan></text> + <text class="SVGTextShape" transform="rotate(-90 824 5258)"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="318px" font-weight="400"><tspan class="TextPosition" x="824" y="5258"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Time (ms)</tspan></tspan></tspan></text> +</svg> +\ No newline at end of file diff --git a/doc/bachelor-thesis/figures/Verify-Client.svg b/doc/bachelor-thesis/figures/Verify-Client.svg @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="160mm" height="90mm" viewBox="0 0 16000 9000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" stroke-width="28.222" stroke-linejoin="round" xml:space="preserve"> + <path fill="rgb(255,255,255)" stroke="none" d="M 7987,8986 L -13,8986 -13,-13 15986,-13 15986,8986 7987,8986 Z"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 8808,7178 L 2230,7178 2230,1461 15386,1461 15386,7178 8808,7178 Z"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,7177 L 2230,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,6033 L 2230,6033"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,4889 L 2230,4889"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,3747 L 2230,3747"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,2603 L 2230,2603"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,1460 L 2230,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2230,7327 L 2230,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2230,7327 L 2230,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 4422,7327 L 4422,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 4422,7327 L 4422,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 6615,7327 L 6615,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 6615,7327 L 6615,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 8807,7327 L 8807,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 8807,7327 L 8807,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 11000,7327 L 11000,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 11000,7327 L 11000,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 13193,7327 L 13193,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 13193,7327 L 13193,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,7327 L 15386,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 15386,7327 L 15386,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2230,7177 L 15386,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2080,7177 L 2230,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2080,7177 L 2230,7177"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2080,6033 L 2230,6033"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2080,6033 L 2230,6033"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2080,4889 L 2230,4889"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2080,4889 L 2230,4889"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2080,3747 L 2230,3747"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2080,3747 L 2230,3747"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2080,2603 L 2230,2603"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2080,2603 L 2230,2603"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2080,1460 L 2230,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2080,1460 L 2230,1460"/> + <path fill="none" stroke="rgb(179,179,179)" stroke-linejoin="round" d="M 2230,7177 L 2230,1460"/> + <path fill="none" stroke="rgb(0,69,134)" stroke-width="80" stroke-linejoin="round" d="M 2230,2603 L 2339,2603 2449,2603 2558,2603 2668,2603 2778,2603 2887,2603 2997,2603 3107,2603 3216,2603 3326,2603 3436,2603 3545,2603 3655,2603 3764,2603 3874,2603 3984,2603 4093,2603 4203,2603 4313,2603 4422,2603 4532,2603 4642,2603 4751,2603 4861,2603 4971,2603 5080,2603 5190,2603 5299,2603 5409,2603 5519,2603 5628,2603 5738,2603 5848,2603 5957,2603 6067,2603 6177,2603 6286,2603 6396,2603 6506,2603 6615,2603 6725,2603 6834,2603 6944,2603 7054,2603 7163,2603 7273,2603 7383,2603 7492,2603 7602,2603 7712,2603 7821,2603 7931,2603 8040,2603 8149,2603 8259,2603 8368,2603 8478,2603 8588,2603 8697,2603 8807,2603 8917,2603 9026,2603 9136,2603 9246,2603 9355,2603 9465,2603 9574,2603 9684,2603 9794,2603 9903,2603 10013,2603 10123,2603 10232,2603 10342,2603 10452,2603 10561,2603 10671,2603 10781,2603 10890,2603 11000,2603 11109,2603 11219,2603 11329,2603 11438,2603 11548,2603 11658,2603 11767,2603 11877,2603 11987,2603 12096,2603 12206,2603 12316,2603 12425,2603 12535,2603 12644,2603 12754,2603 12864,2603 12973,2603 13083,2603 13193,2603 13302,2603 13412,2603 13522,2603 13631,2603 13741,2603 13851,2603 13960,2603 14070,2603 14179,2603 14289,2603 14399,2603 14508,2603 14618,2603 14728,2603 14837,2603 14947,2603 15057,2603 15166,2603 15276,2603 15386,2603"/> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="2137" y="7745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">3</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="4237" y="7745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">40</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="6430" y="7745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">80</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="8530" y="7745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">120</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="10723" y="7745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">160</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="12916" y="7745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">200</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="15109" y="7745"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">240</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1795" y="7298"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">0</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1319" y="6154"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">0.05</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1504" y="5010"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">0.1</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1319" y="3867"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">0.15</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1504" y="2723"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">0.2</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="353px" font-weight="400"><tspan class="TextPosition" x="1319" y="1580"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">0.25</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="459px" font-weight="400"><tspan class="TextPosition" x="6016" y="838"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Frosix Client: Verify</tspan></tspan></tspan></text> + <text class="SVGTextShape"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="318px" font-weight="400"><tspan class="TextPosition" x="7764" y="8392"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">Threshold</tspan></tspan></tspan></text> + <text class="SVGTextShape" transform="rotate(-90 824 5205)"><tspan class="TextParagraph" font-family="Liberation Sans, sans-serif" font-size="318px" font-weight="400"><tspan class="TextPosition" x="824" y="5205"><tspan fill="rgb(0,0,0)" stroke="none" style="white-space: pre">time (ms)</tspan></tspan></tspan></text> +</svg> +\ No newline at end of file diff --git a/doc/bachelor-thesis/figures/frosix_client_authentication_hash.png b/doc/bachelor-thesis/figures/frosix_client_authentication_hash.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_client_authentication_hash_question.png b/doc/bachelor-thesis/figures/frosix_client_authentication_hash_question.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_client_entropy.png b/doc/bachelor-thesis/figures/frosix_client_entropy.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_database.png b/doc/bachelor-thesis/figures/frosix_database.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_delete-key_sequence.png b/doc/bachelor-thesis/figures/frosix_delete-key_sequence.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_dkg_sequence.png b/doc/bachelor-thesis/figures/frosix_dkg_sequence.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_entropy_figures_legend.drawio b/doc/bachelor-thesis/figures/frosix_entropy_figures_legend.drawio @@ -0,0 +1,73 @@ +<mxfile host="Electron" modified="2023-06-11T08:58:36.412Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.3.7 Chrome/112.0.5615.204 Electron/24.5.0 Safari/537.36" etag="cj6dPzhiTJEbk6cwZ7i0" version="21.3.7" type="device"> + <diagram name="Page-1" id="PHIxNanW1tgeCwRJNwyJ"> + <mxGraphModel dx="1379" dy="830" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0"> + <root> + <mxCell id="0" /> + <mxCell id="1" parent="0" /> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-1" value="" style="ellipse;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1"> + <mxGeometry x="40" y="40" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-2" value="" style="ellipse;whiteSpace=wrap;html=1;fillColor=none;fontColor=#000000;strokeColor=#000000;dashed=1;" vertex="1" parent="1"> + <mxGeometry x="440" y="160" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-3" value="" style="ellipse;whiteSpace=wrap;html=1;fillColor=none;fontColor=#000000;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="440" y="220" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-4" value="" style="whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1"> + <mxGeometry x="80" y="280" width="40" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-5" value="" style="ellipse;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1"> + <mxGeometry x="40" y="100" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-7" value="" style="ellipse;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"> + <mxGeometry x="40" y="160" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-8" value="" style="ellipse;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;" vertex="1" parent="1"> + <mxGeometry x="40" y="220" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-9" value="data which is stored in the signing document" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> + <mxGeometry x="200" y="40" width="200" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-10" value="data wich is stored in the providers database" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> + <mxGeometry x="200" y="100" width="200" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-11" value="data stored both in the signing document and in the database" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> + <mxGeometry x="200" y="160" width="200" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-12" value="id of an entry in a provider&#39;s database" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> + <mxGeometry x="200" y="220" width="200" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-13" value="data which is used in the protocol, send over the network but not stored" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> + <mxGeometry x="600" y="220" width="200" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-14" value="" style="ellipse;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="1"> + <mxGeometry x="440" y="40" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-15" value="" style="ellipse;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1"> + <mxGeometry x="440" y="100" width="120" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-16" value="intermediate computations or inputs that are not stored or send over the network" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> + <mxGeometry x="600" y="160" width="200" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-17" value="publicly available information" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> + <mxGeometry x="600" y="40" width="200" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-18" value="secret data, only known to a provider" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> + <mxGeometry x="600" y="100" width="200" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-19" value="cryptographic function" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> + <mxGeometry x="200" y="280" width="200" height="40" as="geometry" /> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-20" value="&quot;TEXT&quot;" style="endArrow=classic;html=1;rounded=0;" edge="1" parent="1"> + <mxGeometry width="50" height="50" relative="1" as="geometry"> + <mxPoint x="440" y="300" as="sourcePoint" /> + <mxPoint x="560" y="300" as="targetPoint" /> + </mxGeometry> + </mxCell> + <mxCell id="9uIJ3c1CNvFck_OvSSBq-21" value="context string to separate the different hash and kdf functions and to always get a different output" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> + <mxGeometry x="600" y="280" width="200" height="40" as="geometry" /> + </mxCell> + </root> + </mxGraphModel> + </diagram> +</mxfile> diff --git a/doc/bachelor-thesis/figures/frosix_entropy_figures_legend.png b/doc/bachelor-thesis/figures/frosix_entropy_figures_legend.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_perf_dkg_combined.png b/doc/bachelor-thesis/figures/frosix_perf_dkg_combined.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_perf_dkg_parties.png b/doc/bachelor-thesis/figures/frosix_perf_dkg_parties.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_perf_dkg_threshold.png b/doc/bachelor-thesis/figures/frosix_perf_dkg_threshold.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_perf_sign_client.png b/doc/bachelor-thesis/figures/frosix_perf_sign_client.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_perf_sign_provider.png b/doc/bachelor-thesis/figures/frosix_perf_sign_provider.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_perf_verify_client.png b/doc/bachelor-thesis/figures/frosix_perf_verify_client.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_provider_dkg-commitment_entropy.png b/doc/bachelor-thesis/figures/frosix_provider_dkg-commitment_entropy.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_provider_dkg-key_entropy.png b/doc/bachelor-thesis/figures/frosix_provider_dkg-key_entropy.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_provider_sign_entropy.png b/doc/bachelor-thesis/figures/frosix_provider_sign_entropy.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_request-challenge_sequence.png b/doc/bachelor-thesis/figures/frosix_request-challenge_sequence.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_server_architecture.png b/doc/bachelor-thesis/figures/frosix_server_architecture.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_sign_sequence.png b/doc/bachelor-thesis/figures/frosix_sign_sequence.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_system_architecture.png b/doc/bachelor-thesis/figures/frosix_system_architecture.png Binary files differ. diff --git a/doc/bachelor-thesis/figures/frosix_system_overview.png b/doc/bachelor-thesis/figures/frosix_system_overview.png Binary files differ. diff --git a/doc/bachelor-thesis/frosix.glg b/doc/bachelor-thesis/frosix.glg @@ -0,0 +1,7 @@ +This is makeindex, version 2.16 [TeX Live 2022] (kpathsea + Thai support). +Scanning style file ./frosix.ist...........................done (27 attributes redefined, 0 ignored). +Scanning input file frosix.glo....done (126 entries accepted, 0 rejected). +Sorting entries....done (955 comparisons). +Generating output file frosix.gls....done (52 lines written, 0 warnings). +Output written in frosix.gls. +Transcript written in frosix.glg. diff --git a/doc/bachelor-thesis/frosix.gls b/doc/bachelor-thesis/frosix.gls @@ -0,0 +1,52 @@ +\glossarysection[\glossarytoctitle]{\glossarytitle}\glossarypreamble +\begin{theglossary}\glossaryheader +\glsgroupheading{A}\relax \glsresetentrylist % +\glossentry{authentication data}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{16}}}% +\glossentry{authentication hash}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{17}}}% +\glossentry{authentication method}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{20}}}% +\glossentry{authentication nonce}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{24}}}\glsgroupskip +\glsgroupheading{B}\relax \glsresetentrylist % +\glossentry{brute-force}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{16}}}\glsgroupskip +\glsgroupheading{C}\relax \glsresetentrylist % +\glossentry{challenge-code}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{19}}}% +\glossentry{commitment}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{20}}}% +\glossentry{context string}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{47}}}\glsgroupskip +\glsgroupheading{F}\relax \glsresetentrylist % +\glossentry{provider}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{2\delimN 3}\delimN + \setentrycounter[]{page}\glsnumberformat{16\delimN 17}\delimN + \setentrycounter[]{page}\glsnumberformat{19}\delimN + \setentrycounter[]{page}\glsnumberformat{22\delimR 30}\delimN + \setentrycounter[]{page}\glsnumberformat{32}\delimN + \setentrycounter[]{page}\glsnumberformat{34\delimR 41}\delimN + \setentrycounter[]{page}\glsnumberformat{43\delimN 44}\delimN + \setentrycounter[]{page}\glsnumberformat{46\delimR 52}\delimN + \setentrycounter[]{page}\glsnumberformat{54}\delimN + \setentrycounter[]{page}\glsnumberformat{57}}}\glsgroupskip +\glsgroupheading{N}\relax \glsresetentrylist % +\glossentry{nonce}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{47}}}\glsgroupskip +\glsgroupheading{S}\relax \glsresetentrylist % +\glossentry{salt}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{22}}}% +\glossentry{secret server salt}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{47}}}% +\glossentry{seed}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{38}}}% +\glossentry{struct}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{31}}}\glsgroupskip +\glsgroupheading{T}\relax \glsresetentrylist % +\glossentry{trusted dealer}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{10}}}\glsgroupskip +\glsgroupheading{Z}\relax \glsresetentrylist % +\glossentry{zero knowledge proof}{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{11}}}% +\end{theglossary}\glossarypostamble diff --git a/doc/bachelor-thesis/frosix.pdf b/doc/bachelor-thesis/frosix.pdf Binary files differ. diff --git a/doc/bachelor-thesis/frosix.tex b/doc/bachelor-thesis/frosix.tex @@ -0,0 +1,216 @@ +%============================ MAIN DOCUMENT ================================ +% define document class +\PassOptionsToPackage{table}{xcolor} +\documentclass[ + a4paper, + BCOR=15mm, % Binding correction + twoside, +% openright, +% headings=openright, + bibliography=totoc, % If enabled add bibliography to TOC + listof=totoc, % If enabled add lists to TOC + monolingual, +% bilingual, + invert-title, +]{bfhthesis} + +\LoadBFHModule{listings,terminal,boxes} +%--------------------------------------------------------------------------- +% Documents paths +%--------------------------------------------------------------------------- +\makeatletter +\def\input@path{{content/}} +%or: \def\input@path{{/path/to/folder/}{/path/to/other/folder/}} +\makeatother +%----------------- Base packages -------------------------------------- +% Include Packages +\usepackage[french,ngerman,main=english]{babel} % https://www.namsu.de/Extra/pakete/Babel.html + +\usepackage{amsmath} % various features to facilitate writing math formulas +\usepackage{amsthm} % enhanced version of latex's newtheorem +\usepackage{amsfonts} % set of miscellaneous TeX fonts that augment the standard CM +\usepackage{amssymb} % mathematical special characters + +\usepackage{siunitx} + +\usepackage{graphicx} % integration of images +\usepackage{float} % floating objects + +\usepackage{caption} % for captions of figures and tables +\usepackage{subcaption} % for subcaptions in subfigures +\usepackage{cite} % use bibtex +\usepackage{wrapfig} + +\usepackage{exscale} % mathematical size corresponds to textsize +\usepackage{multirow} % multirow emables combining rows in tables +\usepackage{multicol} + +\usepackage{longtable} + +\usepackage{parskip} +\usepackage{listings} + +%--------------------------------------------------------------------------- +% Graphics paths +%--------------------------------------------------------------------------- +\graphicspath{{pictures/}{figures/}} +%--------------------------------------------------------------------------- +% Blind text -> for dummy text +%--------------------------------------------------------------------------- +\usepackage{blindtext} +\usepackage{letltxmacro} +\LetLtxMacro{\blindtextblindtext}{\blindtext} + +\RenewDocumentCommand{\blindtext}{O{\value{blindtext}}}{ + \begingroup\color{BFH-Gray}\blindtextblindtext[#1]\endgroup +} +%--------------------------------------------------------------------------- +% Glossary Package +%--------------------------------------------------------------------------- +% the glossaries package uses makeindex +% if you use TeXnicCenter do the following steps: +% - Goto "Ausgabeprofile definieren" (ctrl + F7) +% - Select the profile "LaTeX => PDF" +% - Add in register "Nachbearbeitung" a new "Postprozessoren" point named Glossar +% - Select makeindex.exe in the field "Anwendung" ( ..\MiKTeX x.x\miktex\bin\makeindex.exe ) +% - Add this [ -s "%tm.ist" -t "%tmx.glg" -o "%tm.gls" "%tm.glo" ] in the field "Argumente" +% +% for futher informations go to http://ewus.de/tipp-1029.html +%--------------------------------------------------------------------------- +\usepackage[automake,nonumberlist]{glossaries-extra} +\makeglossaries +\input{content/glossary} +%--------------------------------------------------------------------------- +% Makeindex Package +%--------------------------------------------------------------------------- +\usepackage{makeidx} +\makeindex +%\usepackage{imakeidx} % To produce index +%\makeindex[columns=2,intoc] % Index-Initialisation +%\makeindex[columns=3,columnseprule,columnsep,intoc] +%--------------------------------------------------------------------------- +% Hyperref Package (Create links in a pdf) +%--------------------------------------------------------------------------- +\usepackage[ + ,bookmarks + ,plainpages=false + ,pdfpagelabels + ,pdfusetitle + ,backref = {false} % No index backreference + ,colorlinks = {true} % Color links in a PDF + ,hypertexnames = {true} % no failures "same page(i)" + ,bookmarksopen = {true} % opens the bar on the left side + ,bookmarksopenlevel = {0} % depth of opened bookmarks + ,linkcolor=. + ,filecolor=. + ,urlcolor=. + ,citecolor=. +]{hyperref} +%--------------------------------------------------------------------------- + +%% %% Customize Footer and Headers in Document +%% \KOMAoptions{headsepline,plainheadsepline,footsepline,plainfootsepline}% +%% \setkomafont{headsepline}{\color{BFH-DarkBlue}}% BFH-DarkBlue required bfhcolors +%% \setkomafont{footsepline}{\color{BFH-DarkBlue}}% +%% \lehead*{lehead} % the * character does replace the header on the first chapter page as well +%% \cehead*{cehead} +%% \rehead*{rehead} +%% \lohead*{lohead} +%% \cohead*{cohead} +%% \rohead*{rohead} + +%% \lefoot*{lefoot} +%% \cefoot*{cefoot} +%% \refoot*{refoot} +%% \lofoot*{lofoot} +%% \cofoot*{cofoot} +%% \rofoot*{rofoot} +%--------------------------------------------------------------------------- +\let\cleardoublepage\clearpage % clear white pages between chapters +\counterwithout{figure}{chapter} + +% custom commands +\newcommand{\custind}{\newline \noindent\hspace*{3mm}} + +\begin{document} + +%------------ START FRONT PART ------------ +\frontmatter + +\title{Bachelor's Thesis} +\subtitle{FROSIX: FROST Multiparty Signatures on the Network} +\author{Joel Urech} +\institution{Bern University of Applied Sciences} +\department{Technik und Informatik} +\institute{Informatik} +\version{1.0} +\titlegraphic*{\includegraphics{frosix_logo}} +\advisor{Prof. Dr. Christian Grothoff} +\expert{Markus Nufer} +\degreeprogram{Bachelor of Science in Computer Science} +\setupSignature{ + Joel Urech={}, +} + + +%---------------- BFH tile page ----------------------------------------- +\maketitle +%------------ ABSTRACT ---------------- +\addchap{Abstract} +\input{content/abstract} + +\addchap{Acknowledgments} +\input{content/acknowledgements} + +%------------ TABLEOFCONTENTS ---------------- +\tableofcontents + +%------------ START MAIN PART ------------ +\mainmatter + +\chapter{Introduction} +\input{content/introduction} + +\chapter{Related Work} +\input{content/related_work} + +\chapter{Design} +\input{content/design} + +\chapter{Implementation} +\input{content/implementation} + +\chapter{Project Management} +\input{content/project_plan} + +\chapter{Results and Future Work} +\input{content/future_work} + +%------------ Authorship declaration translated to main language ------------ +\declarationOfAuthorship + +%----------- Bibliography ---------------- +\clearpage +\bibliographystyle{unsrt} +\bibliography{project} % the project.bib file gets loaded + +%------------ List of Figures ------------ +%\listoffigures + +%------------ List of Tables ------------- +%\listoftables + +%------------ List of Listings ----------- +%\lstlistoflistings + +%------------ Glossary ------------------- +\printglossary + +%------------ Index ---------------------- +%\clearpage +%\printindex +%------------ Appendix ---------------- +\appendix +\chapter{REST API documentation}\label{appendix_a} + +\end{document} diff --git a/doc/bachelor-thesis/frosix.tex.bbl b/doc/bachelor-thesis/frosix.tex.bbl diff --git a/doc/bachelor-thesis/frosix.tex.blg b/doc/bachelor-thesis/frosix.tex.blg @@ -0,0 +1,5 @@ +[0] Config.pm:306> INFO - This is Biber 2.18 +[0] Config.pm:309> INFO - Logfile is 'frosix.tex.blg' +[103] biber:340> INFO - === Di Jun 6, 2023, 14:30:14 +[227] Utils.pm:410> ERROR - Cannot find 'frosix.tex.bcf'! +[228] Biber.pm:135> INFO - ERRORS: 1 diff --git a/doc/bachelor-thesis/listings/.gitkeep b/doc/bachelor-thesis/listings/.gitkeep diff --git a/doc/bachelor-thesis/pictures/.gitkeep b/doc/bachelor-thesis/pictures/.gitkeep diff --git a/doc/bachelor-thesis/pictures/frosix_logo.png b/doc/bachelor-thesis/pictures/frosix_logo.png Binary files differ. diff --git a/doc/bachelor-thesis/pictures/project_planning.png b/doc/bachelor-thesis/pictures/project_planning.png Binary files differ. diff --git a/doc/bachelor-thesis/project.bib b/doc/bachelor-thesis/project.bib @@ -0,0 +1,522 @@ + +@misc{knuthwebsite, + author = "Donald Knuth", + title = "Knuth: Computers and Typesetting", + url = "http://www-cs-faculty.stanford.edu/\~{}uno/abcde.html" +} + +@article{neumann:1951, + author = "J. von Neumann", + title = "Various Techniques Used in Connection With Random Digits", + journal = "National Bureau of Standards Applied Mathematics Series", + volume = "3", + pages = "36-38", + year = "1951" +} + +@article{vadhan:2012, + author = "Salil P. Vadhan", + title = "Pseudorandomness", + journal = "Foundation and Trends® in Theoretical Computer Science", + volume = "7", + number = "1-3", + pages = "1-336", + year = "2012" +} + +@article{sobti:2012, + author = "R. Sobti and G. Geetha", + title = "Cryptographic Hash Functions: A Review", + journal = "International Journal of Computer Science Issues (IJCSI)", + volume = "9", + number = "2", + pages = "461-479", + year = "2012" +} + +@book{appliedcryptography, + author = "A. Menezes et al.", + title = "Handbook of Applied Cryptography", + year = "1996", + publisher = "CRC Press", +} + +@misc{cryptoeprint:2010/264, + author = {Hugo Krawczyk}, + title = {Cryptographic Extraction and Key Derivation: The HKDF Scheme}, + howpublished = {Cryptology ePrint Archive, Paper 2010/264}, + year = {2010}, + note = {\url{https://eprint.iacr.org/2010/264}}, + url = {https://eprint.iacr.org/2010/264} +} + +@article{bellare:1996, + author = "M. Bellare et al.", + title = "Keying Hash Functions for Message Authentication", + journal = "Advances in Cryptology - Crypto '96 Proceedings", + year = "1996" +} + +@techreport{RFC8018, + author = {K. Moriarty and B. Kaliski and A. Rusch}, + title = {PKCS \#5: Password-Based Cryptography Specification Version 2.1}, + howpublished = {Internet Requests for Comments}, + type = {RFC}, + number = {8018}, + year = {2017}, + month = {January}, + issn = {2070-1721}, + publisher = {RFC Editor}, + institution = {RFC Editor}, +} + +@inproceedings{argon2, + author = {Biryukov, Alex and Dinu, Daniel and Khovratovich, Dmitry}, + year = {2016}, + month = {03}, + pages = {292-302}, + title = {Argon2: New Generation of Memory-Hard Functions for Password Hashing and Other Applications}, + doi = {10.1109/EuroSP.2016.31} +} + +@article{1006971, + author={Hellman, M.E.}, + journal={IEEE Communications Magazine}, + title={An overview of public key cryptography}, + year={2002}, + volume={40}, + number={5}, + pages={42-49}, + doi={10.1109/MCOM.2002.1006971} +} + +@book{Hankerson2004GuideTE, + title={Guide to Elliptic Curve Cryptography}, + author={Darrel Hankerson and Scott A. Vanstone and Alfred Menezes}, + booktitle={Springer Professional Computing}, + year={2004} +} + +@techreport{irtf-cfrg-ristretto255-decaf448-07, + number = {draft-irtf-cfrg-ristretto255-decaf448-07}, + type = {Internet-Draft}, + institution = {Internet Engineering Task Force}, + publisher = {Internet Engineering Task Force}, + note = {Work in Progress}, + url = {https://datatracker.ietf.org/doc/draft-irtf-cfrg-ristretto255-decaf448/07/}, + author = {Henry de Valence and Jack Grigg and Mike Hamburg and Isis Lovecruft and George Tankersley and Filippo Valsorda}, + title = {{The ristretto255 and decaf448 Groups}}, + pagetotal = 23, + year = 2023, + month = apr, + day = 3 +} + +@InProceedings{10.1007/11745853_14, + author="Bernstein, Daniel J.", + editor="Yung, Moti + and Dodis, Yevgeniy + and Kiayias, Aggelos + and Malkin, Tal", + title="Curve25519: New Diffie-Hellman Speed Records", + booktitle="Public Key Cryptography - PKC 2006", + year="2006", + publisher="Springer Berlin Heidelberg", + address="Berlin, Heidelberg", + pages="207--228", + isbn="978-3-540-33852-9" +} + +@misc{cryptoeprint:2015/673, + author = {Mike Hamburg}, + title = {Decaf: Eliminating cofactors through point compression}, + howpublished = {Cryptology ePrint Archive, Paper 2015/673}, + year = {2015}, + note = {\url{https://eprint.iacr.org/2015/673}}, + url = {https://eprint.iacr.org/2015/673} +} + +@inproceedings{crypto-1989-1727, + title={Efficient Identification and Signatures for Smart Cards}, + booktitle={Advances in Cryptology - CRYPTO '89, 9th Annual International Cryptology Conference, Santa Barbara, California, USA, August 20-24, 1989, Proceedings}, + series={Lecture Notes in Computer Science}, + publisher={Springer}, + volume={435}, + pages={239-252}, + doi={10.1007/0-387-34805-0_22}, + author={Claus-Peter Schnorr}, + year={1989} +} + +@misc{rfc8032, + series = {Request for Comments}, + number = 8032, + howpublished = {RFC 8032}, + publisher = {RFC Editor}, + doi = {10.17487/RFC8032}, + url = {https://www.rfc-editor.org/info/rfc8032}, + author = {Simon Josefsson and Ilari Liusvaara}, + title = {{Edwards-Curve Digital Signature Algorithm (EdDSA)}}, + pagetotal = 60, + year = 2017, + month = jan +} + +@incollection{10.7551/mitpress/12274.003.0048, + author = {Shamir, Adi}, + isbn = {9780262363174}, + title = "{How to Share a Secret (1979)}", + booktitle = "{Ideas That Created the Future: Classic Papers of Computer Science}", + publisher = {The MIT Press}, + year = {2021}, + month = {02}, + doi = {10.7551/mitpress/12274.003.0048}, + url = {https://doi.org/10.7551/mitpress/12274.003.0048}, + eprint = {https://direct.mit.edu/book/chapter-pdf/2095304/9780262363174\_c004500.pdf}, +} + +@inproceedings{10.1109/SFCS.1987.4, + author = {Feldman, Paul}, + title = {A Practical Scheme for Non-Interactive Verifiable Secret Sharing}, + year = {1987}, + isbn = {0818608072}, + publisher = {IEEE Computer Society}, + address = {USA}, + url = {https://doi.org/10.1109/SFCS.1987.4}, + doi = {10.1109/SFCS.1987.4}, + booktitle = {Proceedings of the 28th Annual Symposium on Foundations of Computer Science}, + pages = {427–438}, + numpages = {12}, + series = {SFCS '87} +} + +@InProceedings{10.1007/3-540-46416-6_47, + author="Pedersen, Torben Pryds", + editor="Davies, Donald W.", + title="A Threshold Cryptosystem without a Trusted Party", + booktitle="Advances in Cryptology --- EUROCRYPT '91", + year="1991", + publisher="Springer Berlin Heidelberg", + address="Berlin, Heidelberg", + pages="522--526", + isbn="978-3-540-46416-7" +} + +@misc{cryptoeprint:2020/1390, + author = {Jean-Philippe Aumasson and Adrian Hamelink and Omer Shlomovits}, + title = {A Survey of ECDSA Threshold Signing}, + howpublished = {Cryptology ePrint Archive, Paper 2020/1390}, + year = {2020}, + note = {\url{https://eprint.iacr.org/2020/1390}}, + url = {https://eprint.iacr.org/2020/1390} +} + +@misc{cryptoeprint:2020/852, + author = {Chelsea Komlo and Ian Goldberg}, + title = {FROST: Flexible Round-Optimized Schnorr Threshold Signatures}, + howpublished = {Cryptology ePrint Archive, Paper 2020/852}, + year = {2020}, + note = {\url{https://eprint.iacr.org/2020/852}}, + url = {https://eprint.iacr.org/2020/852} +} + +@misc{secg:sec1-v2, + author = {Daniel R. L. Brown}, + title = {SEC 1: Elliptic Curve Cryptography}, + year = {2009}, + url = {https://www.secg.org/sec1-v2.pdf} +} + +@misc{ckomlo:frost, + author = "Chelsea Komlo", + title = "frost", + year = "2021", + howpublished = {\url{https://git.uwaterloo.ca/ckomlo/frost}}, + commit = "63b04efd5032be92002abe1a614d158cf9ea8c7b" +} + +@misc{zcash:frost, + author = "Zcash Foundation", + title = "frost", + year = "2023", + howpublished = {\url{https://github.com/ZcashFoundation/frost}}, + commit = "a6886e4a3fc63caa8d6c98ee99dd2bffd54823c5" +} + +@misc{coinbase:frost, + author = "Coinbase", + title = "kryptology", + year = "2022", + howpublished = {\url{https://github.com/coinbase/kryptology}}, + commit = "f7f15f217682f3e13b88846a419bce94bc3f7f73" +} + +@misc{taurusgroup:frost, + author = "Taurus Group", + title = "frost-ed25519", + year = "2021", + howpublished = {\url{https://github.com/taurusgroup/frost-ed25519}}, + commit = "5abc84a4dba755f25d03e9f59e3e5fde0c92369c" +} + +@misc{lovecruft:frost, + author = "Isis Agora Lovecruft", + title = "frost-dalek", + year = "2021", + howpublished = {\url{https://github.com/isislovecruft/frost-dalek}}, + commit = "9645caf8f2dd881b8bc7b62edc8a048344b71630" +} + +@misc{cloudflare:frost, + author = "Cloudflare", + title = "circl - frostyflakes", + year = "2022", + howpublished = {\url{https://github.com/cloudflare/circl/tree/frostyflakes/tss/frost}}, + commit = "735811d11cf955d311255b0f9c83d5afec17e990" +} + +@misc{trust-machines:frost, + author = "Trust Machines", + title = "WTFROST", + year = "2023", + howpublished = {\url{https://github.com/Trust-Machines/frost}}, + commit = "a85d2735c9c1bc71d0a5bd69eadd1679e6d45233" +} + +@techreport{irtf-cfrg-frost-13, + number = {draft-irtf-cfrg-frost-13}, + type = {Internet-Draft}, + institution = {Internet Engineering Task Force}, + publisher = {Internet Engineering Task Force}, + note = {Work in Progress}, + url = {https://datatracker.ietf.org/doc/draft-irtf-cfrg-frost/13/}, + author = {Deirdre Connolly and Chelsea Komlo and Ian Goldberg and Christopher A. Wood}, + title = {{Two-Round Threshold Schnorr Signatures with FROST}}, + pagetotal = 59, + year = 2023, + month = may, + day = 8 +} + +@misc{weighted-frost, + author = "Joey Yandle", + title = "Weighted Threshold FROST", + year = "2023", + howpublished = {\url{https://trust-machines.github.io/frost/wtf.pdf}} +} + +@misc{cryptoeprint:2021/1055, + author = {François Garillot and Yashvanth Kondi and Payman Mohassel and Valeria Nikolaenko}, + title = {Threshold Schnorr with Stateless Deterministic Signing from Standard Assumptions}, + howpublished = {Cryptology ePrint Archive, Paper 2021/1055}, + year = {2021}, + note = {\url{https://eprint.iacr.org/2021/1055}}, + url = {https://eprint.iacr.org/2021/1055} +} + +@inproceedings{10.5555/648120.747057, + author = {Bellare, Mihir and Boldyreva, Alexandra and Staddon, Jessica}, + title = {Randomness Re-Use in Multi-Recipient Encryption Schemes}, + year = {2003}, + isbn = {354000324X}, + publisher = {Springer-Verlag}, + address = {Berlin, Heidelberg}, + booktitle = {Proceedings of the 6th International Workshop on Theory and Practice in Public Key Cryptography: Public Key Cryptography}, + pages = {85–99}, + numpages = {15}, + keywords = {encryption, randomness, provable security, broadcast encryption}, + series = {PKC '03} +} + +@misc{cryptoeprint:2021/1375, + author = {Elizabeth Crites and Chelsea Komlo and Mary Maller}, + title = {How to Prove Schnorr Assuming Schnorr: Security of Multi- and Threshold Signatures}, + howpublished = {Cryptology ePrint Archive, Paper 2021/1375}, + year = {2021}, + note = {\url{https://eprint.iacr.org/2021/1375}}, + url = {https://eprint.iacr.org/2021/1375} +} + + +@book{Peralta_Brandão_2023, + title={NIST First Call for Multi-Party Threshold Schemes}, + url={http://dx.doi.org/10.6028/NIST.IR.8214C.ipd}, + DOI={10.6028/nist.ir.8214c.ipd}, + institution={National Institute of Standards and Technology}, + author={Peralta, René and Brandão, Luís T.A.N.}, + year={2023}, + month={Jan} +} + +@misc{taproot, + author = {Shawn Amick}, + year = {2021}, + title = {Understanding Taproot In A Simple Way}, + note = {\url{https://bitcoinmagazine.com/technical/understanding-taproot-in-a-simple-way}, + last accessed on 2023-06-07} +} + +@misc{zcash:perf, + author = {Conrado Gouvêa}, + year = {2023}, + title = {FROST Performance}, + note = {\url{https://zfnd.org/frost-performance/}, + last accessed on 2023-06-07} +} + +@misc{anastasis, + author = "Anastasis SARL", + title = "GNU Anastasis", + year = "2023", + howpublished = {\url{https://git.taler.net/anastasis.git/}}, + commit = "d4ab34a799965efed34bbb442710ee46dd99a32c" +} + +@misc{fsf, + author = {Free Software Foundation}, + year = {2023}, + title = {What is Free Software?}, + note = {\url{https://www.gnu.org/philosophy/free-sw.html}, + last accessed on 2023-06-07} +} + +@misc{heise:msi-hack, + author = {Dirk Knop}, + year = {2023}, + title = {MSI-Hack: Intel Bootguard- und Firmware-Signatur-Schlüssel in freier Wildbahn}, + note = {\url{https://www.heise.de/news/MSI-Hack-Intel-Bootguard-und-Firmware-Signatur-Schluessel-in-freier-Wildbahn-8989300.html}, + last accessed on 2023-06-09} +} + +@misc{schneier:leaked-keys, + author = {Bruce Schneier}, + year = {2022}, + title = {Leaked Signing Keys Are Being Used to Sign Malware}, + note = {\url{https://www.schneier.com/blog/archives/2022/12/leaked-signing-keys-are-being-used-to-sign-malware.html}, + last accessed on 2023-06-09} +} + +@misc{github:stolen-keys, + author = {Alexis Wales}, + year = {2023}, + title = {Action needed for GitHub Desktop and Atom users}, + note = {\url{https://github.blog/2023-01-30-action-needed-for-github-desktop-and-atom-users/}, + last accessed on 2023-06-09} +} + +@misc{malwarebytes:nvidia-keys, + author = {Pieter Arntz}, + year = {2022}, + title = {Stolen Nvidia certificates used to sign malware - here's what to do}, + note = {\url{https://www.malwarebytes.com/blog/news/2022/03/stolen-nvidia-certificates-used-to-sign-malware-heres-what-to-do}, + last accessed on 2023-06-09} +} + +@techreport{IR8320, + author = {National Institute of Standards and Technology}, + title = {Hardware-Enabled Security}, + institution = {U.S. Department of Commerce}, + DOI = {10.6028/nist.ir.8320}, + year = {2022}, +} + +@misc{admin:qes, + author = {Swiss Accreditation Service SAS}, + title = {Electronic Signature}, + institution = {Swiss Accreditation Service SAS}, + year = {2021}, + note = {\url{https://www.sas.admin.ch/sas/en/home/akkreditiertestellen/akkrstellensuchesas/pki1.html}, + last accessed on 2023-06-10} +} + + +@misc{bit:qes, + author = {Federal Office of Information Technology, Systems and Telecommunication FOITT}, + title = {Commercial certification service providers}, + year = {2023}, + note = {\url{https://www.bit.admin.ch/bit/en/home/themes/elektronische-signatur/signieren/angebote-privatwirtschaft.html}, + last accessed on 2023-06-10} +} + +@techreport{anastasis-thesis, + author = {Dominik S. Meister, Dennis Neufeld}, + title = {Anastasis - Password-less key recovery via multi-factor multi-party authentication}, + year = {2020}, + institution = {Bern University of Applied Sciences} +} + +@misc{libsodium, + title = {Sodium}, + note = {\url{https://doc.libsodium.org/}} +} + +@misc{libgnunet, + title = {GNUnet}, + note = {\url{https://www.gnunet.org/en/}} +} + +@misc{libcurl, + title = {libcurl}, + note = {\url{https://curl.se/libcurl/}} +} + +@misc{libmicrohttpd, + title = {GNU libmicrohttpd}, + note = {\url{https://www.gnu.org/software/libmicrohttpd/}} +} + +@misc{postgresql, + title = {PostgreSQL}, + note = {\url{https://www.postgresql.org/}} +} + +@misc{libjansson, + title = {Jansson}, + note = {\url{https://jansson.readthedocs.io/en/latest/}} +} + +@misc{libtaler, + title = {GNU Taler}, + note = {\url{https://taler.net/en/index.html}} +} + +@misc{bitcoin:multisig, + author = {Jon Hodl}, + year = {2023}, + title = {MultiSig: Multiple Signatures}, + note = {\url{https://www.whatisbitcoin.com/learn/what-is-multisig}, + last accessed on 2023-06-11} +} + +@inproceedings{10.1145/3548606.3560583, + author = {Ruffing, Tim and Ronge, Viktoria and Jin, Elliott and Schneider-Bensch, Jonas and Schr\"{o}der, Dominique}, + title = {ROAST: Robust Asynchronous Schnorr Threshold Signatures}, + year = {2022}, + isbn = {9781450394505}, + publisher = {Association for Computing Machinery}, + address = {New York, NY, USA}, + url = {https://doi.org/10.1145/3548606.3560583}, + doi = {10.1145/3548606.3560583}, + booktitle = {Proceedings of the 2022 ACM SIGSAC Conference on Computer and Communications Security}, + pages = {2551–2564}, + numpages = {14}, + keywords = {threshold signatures, robustness, frost, schnorr signatures}, + location = {Los Angeles, CA, USA}, + series = {CCS '22} +} + +@misc{frosix, + author = {Joel Urech}, + year = {2023}, + title = {Frosix}, + note = {\url{https://git.taler.net/frosix.git/}} +} + +@misc{cryptoeprint:2004/035, + author = {Phillip Rogaway and Thomas Shrimpton}, + title = {Cryptographic Hash-Function Basics: Definitions, Implications and Separations for Preimage Resistance, Second-Preimage Resistance, and Collision Resistance}, + howpublished = {Cryptology ePrint Archive, Paper 2004/035}, + year = {2004}, + note = {\url{https://eprint.iacr.org/2004/035}}, + url = {https://eprint.iacr.org/2004/035} +} diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am @@ -0,0 +1,11 @@ +# This Makefile.am is in the public domain + + +all: frosix.doxy + doxygen $< + +clean: + rm -rf html + +EXTRA_DIST = \ + frosix.doxy diff --git a/doc/doxygen/frosix.doxy b/doc/doxygen/frosix.doxy @@ -0,0 +1,303 @@ +# Doxyfile 1.5.6 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "Frosix" +PROJECT_NUMBER = 0.0.1 +PROJECT_LOGO = +OUTPUT_DIRECTORY = . +CREATE_SUBDIRS = YES +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = ../.. +STRIP_FROM_INC_PATH = ../../src/include \ + src/include \ + include +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = YES +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = NO +SORT_BRIEF_DOCS = NO +SORT_GROUP_NAMES = YES +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = ../../src +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.vhd \ + *.vhdl \ + *.C \ + *.CC \ + *.C++ \ + *.II \ + *.I++ \ + *.H \ + *.HH \ + *.H++ \ + *.CS \ + *.PHP \ + *.PHP3 \ + *.M \ + *.MM \ + *.PY \ + *.F90 \ + *.F \ + *.VHD \ + *.VHDL +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = */test_* \ + */.svn/* \ + */.git/* \ + */perf_* .* \ + .* \ +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = YES +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +IGNORE_PREFIX = FROST_ +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +GENERATE_HTMLHELP = NO +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Frosix Source Documentation" +DOCSET_BUNDLE_ID = net.taler +HTML_DYNAMIC_SECTIONS = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NONE +TREEVIEW_WIDTH = 250 +FORMULA_FONTSIZE = 10 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = YES +PAPER_TYPE = a4 +EXTRA_PACKAGES = amsmath,amssymb +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = GNUNET_UNUSED="" GNUNET_PACKED="" +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = frosix.tag +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = NO +COLLABORATION_GRAPH = NO +GROUP_GRAPHS = NO +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = YES +CALLER_GRAPH = YES +GRAPHICAL_HIERARCHY = NO +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = svg +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 100 +MAX_DOT_GRAPH_DEPTH = 2 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = YES diff --git a/doc/sphinx/Makefile b/doc/sphinx/Makefile @@ -0,0 +1,191 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. You can find Sphinx at http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext +.PHONY: texinfo-exchange + +help: + @echo "Please use \`make <target>' where <target> is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + + + + + +# The html-linked builder does not support caching, so we +# remove all cached state first. +html: +# -W = exit 1 on warning; --keep-going = complete build anyway; -w /tmp/sphinx-warnings.log = write log to ~/warnings.log + $(SPHINXBUILD) -b html-linked $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/neuro.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/neuro.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/neuro" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/neuro" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +texinfo-exchange: + $(SPHINXBUILD) -b texinfo . $(BUILDDIR)/texinfo-exchange ./taler-bank.rst -D master_doc=taler-exchange + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo-exchange." + @echo "Run \`make' in that directory to run these through makeinfo" + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/doc/sphinx/README b/doc/sphinx/README @@ -0,0 +1,14 @@ +This repository contains the documentation for all main GNU Taler components. + +To build things on a Debian (-based) system, install these packages: + - make + - python3-sphinx + - python3-recommonmark + - graphviz + - texlive-latex-extra + - dvipng + +Then, do "make html" for HTML, "make texinfo" for Texinfo, etc. +(Do "make" w/o a target to see a list of possible targets.) + +The output is in subdir ‘_build’. diff --git a/doc/sphinx/_exts/__pycache__/ebicsdomain.cpython-310.pyc b/doc/sphinx/_exts/__pycache__/ebicsdomain.cpython-310.pyc Binary files differ. diff --git a/doc/sphinx/_exts/__pycache__/typescriptdomain.cpython-310.pyc b/doc/sphinx/_exts/__pycache__/typescriptdomain.cpython-310.pyc Binary files differ. diff --git a/doc/sphinx/_exts/ebicsdomain.py b/doc/sphinx/_exts/ebicsdomain.py @@ -0,0 +1,229 @@ +""" +EBICS documentation domain. + +:copyright: Copyright 2019 by Taler Systems SA +:license: LGPLv3+ +:author: Florian Dold +""" + +import re +import unicodedata + +from docutils import nodes +from typing import List, Optional, Iterable, Dict, Tuple +from typing import cast + +from docutils import nodes +from docutils.nodes import Element, Node +from docutils.statemachine import StringList + +from sphinx import addnodes +from sphinx.roles import XRefRole +from sphinx.domains import Domain, ObjType, Index +from sphinx.directives import directives +from sphinx.util.docutils import SphinxDirective +from sphinx.util.nodes import make_refnode +from sphinx.util import logging + +logger = logging.getLogger(__name__) + +def make_glossary_term(env: "BuildEnvironment", textnodes: Iterable[Node], index_key: str, + source: str, lineno: int, new_id: str = None) -> nodes.term: + # get a text-only representation of the term and register it + # as a cross-reference target + term = nodes.term('', '', *textnodes) + term.source = source + term.line = lineno + + gloss_entries = env.temp_data.setdefault('gloss_entries', set()) + termtext = term.astext() + if new_id is None: + new_id = nodes.make_id('ebics-order-' + termtext.lower()) + if new_id == 'ebics-order': + # the term is not good for node_id. Generate it by sequence number instead. + new_id = 'ebics-order-%d' % env.new_serialno('ebics') + while new_id in gloss_entries: + new_id = 'ebics-order-%d' % env.new_serialno('ebics') + gloss_entries.add(new_id) + + ebics = env.get_domain('ebics') + ebics.add_object('order', termtext.lower(), env.docname, new_id) + + term['ids'].append(new_id) + term['names'].append(new_id) + + return term + + +def split_term_classifiers(line: str) -> List[Optional[str]]: + # split line into a term and classifiers. if no classifier, None is used.. + parts = re.split(' +: +', line) + [None] + return parts + + +class EbicsOrders(SphinxDirective): + has_content = True + required_arguments = 0 + optional_arguments = 0 + final_argument_whitespace = False + option_spec = { + 'sorted': directives.flag, + } + + def run(self): + node = addnodes.glossary() + node.document = self.state.document + + # This directive implements a custom format of the reST definition list + # that allows multiple lines of terms before the definition. This is + # easy to parse since we know that the contents of the glossary *must + # be* a definition list. + + # first, collect single entries + entries = [] # type: List[Tuple[List[Tuple[str, str, int]], StringList]] + in_definition = True + in_comment = False + was_empty = True + messages = [] # type: List[nodes.Node] + for line, (source, lineno) in zip(self.content, self.content.items): + # empty line -> add to last definition + if not line: + if in_definition and entries: + entries[-1][1].append('', source, lineno) + was_empty = True + continue + # unindented line -> a term + if line and not line[0].isspace(): + # enable comments + if line.startswith('.. '): + in_comment = True + continue + else: + in_comment = False + + # first term of definition + if in_definition: + if not was_empty: + messages.append(self.state.reporter.warning( + _('glossary term must be preceded by empty line'), + source=source, line=lineno)) + entries.append(([(line, source, lineno)], StringList())) + in_definition = False + # second term and following + else: + if was_empty: + messages.append(self.state.reporter.warning( + _('glossary terms must not be separated by empty lines'), + source=source, line=lineno)) + if entries: + entries[-1][0].append((line, source, lineno)) + else: + messages.append(self.state.reporter.warning( + _('glossary seems to be misformatted, check indentation'), + source=source, line=lineno)) + elif in_comment: + pass + else: + if not in_definition: + # first line of definition, determines indentation + in_definition = True + indent_len = len(line) - len(line.lstrip()) + if entries: + entries[-1][1].append(line[indent_len:], source, lineno) + else: + messages.append(self.state.reporter.warning( + _('glossary seems to be misformatted, check indentation'), + source=source, line=lineno)) + was_empty = False + + # now, parse all the entries into a big definition list + items = [] + for terms, definition in entries: + termtexts = [] # type: List[str] + termnodes = [] # type: List[nodes.Node] + system_messages = [] # type: List[nodes.Node] + for line, source, lineno in terms: + parts = split_term_classifiers(line) + # parse the term with inline markup + # classifiers (parts[1:]) will not be shown on doctree + textnodes, sysmsg = self.state.inline_text(parts[0], lineno) + + # use first classifier as a index key + term = make_glossary_term(self.env, textnodes, parts[1], source, lineno) + term.rawsource = line + system_messages.extend(sysmsg) + termtexts.append(term.astext()) + termnodes.append(term) + + termnodes.extend(system_messages) + + defnode = nodes.definition() + if definition: + self.state.nested_parse(definition, definition.items[0][1], + defnode) + termnodes.append(defnode) + items.append((termtexts, + nodes.definition_list_item('', *termnodes))) + + if 'sorted' in self.options: + items.sort(key=lambda x: + unicodedata.normalize('NFD', x[0][0].lower())) + + node["sorted"] = 'sorted' in self.options + + dlist = nodes.definition_list() + dlist['classes'].append('glossary') + dlist.extend(item[1] for item in items) + node += dlist + return messages + [node] + + +class EbicsDomain(Domain): + """Ebics domain.""" + + name = 'ebics' + label = 'EBICS' + + object_types = { + 'order': ObjType('order', 'ebics'), + } + + directives = { + 'orders': EbicsOrders, + } + + roles = { + 'order': XRefRole(lowercase=True, warn_dangling=True, innernodeclass=nodes.inline), + } + + dangling_warnings = { + 'order': 'undefined EBICS order type: %(target)s', + } + + @property + def objects(self) -> Dict[Tuple[str, str], Tuple[str, str]]: + return self.data.setdefault('objects', {}) # (objtype, name) -> docname, labelid + + def clear_doc(self, docname): + for key, (fn, _l) in list(self.objects.items()): + if fn == docname: + del self.objects[key] + + def resolve_xref(self, env, fromdocname, builder, typ, target, + node, contnode): + try: + info = self.objects[(str(typ), str(target))] + except KeyError: + return None + else: + anchor = "ebics-order-{}".format(str(target)) + title = typ.upper() + ' ' + target + return make_refnode(builder, fromdocname, info[0], anchor, + contnode, title) + + def add_object(self, objtype: str, name: str, docname: str, labelid: str) -> None: + self.objects[objtype, name] = (docname, labelid) + + +def setup(app): + app.add_domain(EbicsDomain) diff --git a/doc/sphinx/_exts/httpdomain/__init__.py b/doc/sphinx/_exts/httpdomain/__init__.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +""" + sphinxcontrib + ~~~~~~~~~~~~~ + + This package is a namespace package that contains all extensions + distributed in the ``sphinx-contrib`` distribution. + + :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +__import__('pkg_resources').declare_namespace(__name__) + diff --git a/doc/sphinx/_exts/httpdomain/__pycache__/__init__.cpython-310.pyc b/doc/sphinx/_exts/httpdomain/__pycache__/__init__.cpython-310.pyc Binary files differ. diff --git a/doc/sphinx/_exts/httpdomain/__pycache__/httpdomain.cpython-310.pyc b/doc/sphinx/_exts/httpdomain/__pycache__/httpdomain.cpython-310.pyc Binary files differ. diff --git a/doc/sphinx/_exts/httpdomain/autohttp/__init__.py b/doc/sphinx/_exts/httpdomain/autohttp/__init__.py @@ -0,0 +1,11 @@ +""" + sphinxcontrib.autohttp + ~~~~~~~~~~~~~~~~~~~~~~ + + The sphinx.ext.autodoc-style HTTP API reference builder + for sphinxcontrib.httpdomain. + + :copyright: Copyright 2011 by Hong Minhee + :license: BSD, see LICENSE for details. + +""" diff --git a/doc/sphinx/_exts/httpdomain/autohttp/bottle.py b/doc/sphinx/_exts/httpdomain/autohttp/bottle.py @@ -0,0 +1,114 @@ +""" + sphinxcontrib.autohttp.bottle + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The sphinx.ext.autodoc-style HTTP API reference builder (from Bottle) + for sphinxcontrib.httpdomain. + + :copyright: Copyright 2012 by Jameel Al-Aziz + :license: BSD, see LICENSE for details. + +""" + +import re +import six + +from docutils import nodes +from docutils.parsers.rst import directives +from docutils.statemachine import ViewList + +from sphinx.util import force_decode +from sphinx.util.compat import Directive +from sphinx.util.nodes import nested_parse_with_titles +from sphinx.util.docstrings import prepare_docstring +from sphinx.pycode import ModuleAnalyzer + +from sphinxcontrib import httpdomain +from sphinxcontrib.autohttp.common import http_directive, import_object + + +def translate_bottle_rule(app, rule): + buf = six.StringIO() + if hasattr(app.router, "parse_rule"): + iterator = app.router.parse_rule(rule) # bottle 0.11 + else: + iterator = app.router._itertokens(rule) # bottle 0.12 + for name, filter, conf in iterator: + if filter: + buf.write('(') + buf.write(name) + if (filter != app.router.default_filter and filter != 'default')\ + or conf: + buf.write(':') + buf.write(filter) + if conf: + buf.write(':') + buf.write(conf) + buf.write(')') + else: + buf.write(name) + return buf.getvalue() + + +def get_routes(app): + for route in app.routes: + path = translate_bottle_rule(app, route.rule) + yield route.method, path, route + + +class AutobottleDirective(Directive): + + has_content = True + required_arguments = 1 + option_spec = {'endpoints': directives.unchanged, + 'undoc-endpoints': directives.unchanged, + 'include-empty-docstring': directives.unchanged} + + @property + def endpoints(self): + endpoints = self.options.get('endpoints', None) + if not endpoints: + return None + return frozenset(re.split(r'\s*,\s*', endpoints)) + + @property + def undoc_endpoints(self): + undoc_endpoints = self.options.get('undoc-endpoints', None) + if not undoc_endpoints: + return frozenset() + return frozenset(re.split(r'\s*,\s*', undoc_endpoints)) + + def make_rst(self): + app = import_object(self.arguments[0]) + for method, path, target in get_routes(app): + endpoint = target.name or target.callback.__name__ + if self.endpoints and endpoint not in self.endpoints: + continue + if endpoint in self.undoc_endpoints: + continue + view = target.callback + docstring = view.__doc__ or '' + if not isinstance(docstring, six.text_type): + analyzer = ModuleAnalyzer.for_module(view.__module__) + docstring = force_decode(docstring, analyzer.encoding) + if not docstring and 'include-empty-docstring' not in self.options: + continue + docstring = prepare_docstring(docstring) + for line in http_directive(method, path, docstring): + yield line + + def run(self): + node = nodes.section() + node.document = self.state.document + result = ViewList() + for line in self.make_rst(): + result.append(line, '<autobottle>') + nested_parse_with_titles(self.state, result, node) + return node.children + + +def setup(app): + if 'http' not in app.domains: + httpdomain.setup(app) + app.add_directive('autobottle', AutobottleDirective) + diff --git a/doc/sphinx/_exts/httpdomain/autohttp/common.py b/doc/sphinx/_exts/httpdomain/autohttp/common.py @@ -0,0 +1,36 @@ +""" + sphinxcontrib.autohttp.common + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The common functions for web framework reflection. + + :copyright: Copyright 2011 by Hong Minhee + :license: BSD, see LICENSE for details. + +""" +import six +from six.moves import builtins +from six.moves import reduce + +def import_object(import_name): + module_name, expr = import_name.split(':', 1) + mod = __import__(module_name) + mod = reduce(getattr, module_name.split('.')[1:], mod) + globals = builtins + if not isinstance(globals, dict): + globals = globals.__dict__ + return eval(expr, globals, mod.__dict__) + + +def http_directive(method, path, content): + method = method.lower().strip() + if isinstance(content, six.string_types): + content = content.splitlines() + yield '' + paths = [path] if isinstance(path, six.string_types) else path + for path in paths: + yield '.. http:{method}:: {path}'.format(**locals()) + yield '' + for line in content: + yield ' ' + line + yield '' diff --git a/doc/sphinx/_exts/httpdomain/autohttp/flask.py b/doc/sphinx/_exts/httpdomain/autohttp/flask.py @@ -0,0 +1,48 @@ +""" + sphinxcontrib.autohttp.flask + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The sphinx.ext.autodoc-style HTTP API reference builder (from Flask) + for sphinxcontrib.httpdomain. + + :copyright: Copyright 2011 by Hong Minhee + :license: BSD, see LICENSE for details. + +""" +from __future__ import absolute_import + +import re +import itertools +import six + +from docutils import nodes +from docutils.parsers.rst import directives +from docutils.statemachine import ViewList + +from sphinx.util import force_decode +from sphinx.util.compat import Directive +from sphinx.util.nodes import nested_parse_with_titles +from sphinx.util.docstrings import prepare_docstring +from sphinx.pycode import ModuleAnalyzer + +from sphinxcontrib import httpdomain +from sphinxcontrib.autohttp.common import http_directive, import_object + +from .flask_base import AutoflaskBase + +class AutoflaskDirective(AutoflaskBase): + + def run(self): + node = nodes.section() + node.document = self.state.document + result = ViewList() + for line in self.make_rst(): + result.append(line, '<autoflask>') + nested_parse_with_titles(self.state, result, node) + return node.children + + +def setup(app): + if 'http' not in app.domains: + httpdomain.setup(app) + app.add_directive('autoflask', AutoflaskDirective) diff --git a/doc/sphinx/_exts/httpdomain/autohttp/flask_base.py b/doc/sphinx/_exts/httpdomain/autohttp/flask_base.py @@ -0,0 +1,215 @@ +""" + sphinxcontrib.autohttp.flask + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The sphinx.ext.autodoc-style HTTP API reference builder (from Flask) + for sphinxcontrib.httpdomain. + + :copyright: Copyright 2011 by Hong Minhee + :license: BSD, see LICENSE for details. + +""" + +import re +import itertools +import six + +from docutils import nodes +from docutils.parsers.rst import directives +from docutils.statemachine import ViewList + +from sphinx.util import force_decode +from sphinx.util.compat import Directive +from sphinx.util.nodes import nested_parse_with_titles +from sphinx.util.docstrings import prepare_docstring +from sphinx.pycode import ModuleAnalyzer + +from sphinxcontrib import httpdomain +from sphinxcontrib.autohttp.common import http_directive, import_object + + +def translate_werkzeug_rule(rule): + from werkzeug.routing import parse_rule + buf = six.StringIO() + for conv, arg, var in parse_rule(rule): + if conv: + buf.write('(') + if conv != 'default': + buf.write(conv) + buf.write(':') + buf.write(var) + buf.write(')') + else: + buf.write(var) + return buf.getvalue() + + +def get_routes(app, endpoint=None, order=None): + endpoints = [] + for rule in app.url_map.iter_rules(endpoint): + url_with_endpoint = ( + six.text_type(next(app.url_map.iter_rules(rule.endpoint))), + rule.endpoint + ) + if url_with_endpoint not in endpoints: + endpoints.append(url_with_endpoint) + if order == 'path': + endpoints.sort() + endpoints = [e for _, e in endpoints] + for endpoint in endpoints: + methodrules = {} + for rule in app.url_map.iter_rules(endpoint): + methods = rule.methods.difference(['OPTIONS', 'HEAD']) + path = translate_werkzeug_rule(rule.rule) + for method in methods: + if method in methodrules: + methodrules[method].append(path) + else: + methodrules[method] = [path] + for method, paths in methodrules.items(): + yield method, paths, endpoint + + +def quickref_directive(method, path, content): + rcomp = re.compile("^\s*.. :quickref:\s*(?P<quick>.*)$") + method = method.lower().strip() + if isinstance(content, six.string_types): + content = content.splitlines() + description="" + name="" + ref = path.replace("<","(").replace(">",")").replace("/","-").replace(":","-") + for line in content: + qref = rcomp.match(line) + if qref: + quickref = qref.group("quick") + parts = quickref.split(";",1) + if len(parts)>1: + name = parts[0] + description= parts[1] + else: + description= quickref + break + + row ={} + row['name'] = name + row['operation'] = ' - `%s %s <#%s-%s>`_' % (method.upper(), path, method.lower(), ref) + row['description'] = description + + return row + +class AutoflaskBase(Directive): + + has_content = True + required_arguments = 1 + option_spec = {'endpoints': directives.unchanged, + 'blueprints': directives.unchanged, + 'modules': directives.unchanged, + 'order': directives.unchanged, + 'undoc-endpoints': directives.unchanged, + 'undoc-blueprints': directives.unchanged, + 'undoc-modules': directives.unchanged, + 'undoc-static': directives.unchanged, + 'include-empty-docstring': directives.unchanged} + + @property + def endpoints(self): + endpoints = self.options.get('endpoints', None) + if not endpoints: + return None + return re.split(r'\s*,\s*', endpoints) + + @property + def undoc_endpoints(self): + undoc_endpoints = self.options.get('undoc-endpoints', None) + if not undoc_endpoints: + return frozenset() + return frozenset(re.split(r'\s*,\s*', undoc_endpoints)) + + @property + def blueprints(self): + blueprints = self.options.get('blueprints', None) + if not blueprints: + return None + return frozenset(re.split(r'\s*,\s*', blueprints)) + + @property + def undoc_blueprints(self): + undoc_blueprints = self.options.get('undoc-blueprints', None) + if not undoc_blueprints: + return frozenset() + return frozenset(re.split(r'\s*,\s*', undoc_blueprints)) + + @property + def modules(self): + modules = self.options.get('modules', None) + if not modules: + return frozenset() + return frozenset(re.split(r'\s*,\s*', modules)) + + @property + def undoc_modules(self): + undoc_modules = self.options.get('undoc-modules', None) + if not undoc_modules: + return frozenset() + return frozenset(re.split(r'\s*,\s*', undoc_modules)) + + @property + def order(self): + order = self.options.get('order', None) + if order not in (None, 'path'): + raise ValueError('Invalid value for :order:') + return order + + def make_rst(self, qref=False): + app = import_object(self.arguments[0]) + if self.endpoints: + routes = itertools.chain(*[get_routes(app, endpoint, self.order) + for endpoint in self.endpoints]) + else: + routes = get_routes(app, order=self.order) + for method, paths, endpoint in routes: + try: + blueprint, _, endpoint_internal = endpoint.rpartition('.') + if self.blueprints and blueprint not in self.blueprints: + continue + if blueprint in self.undoc_blueprints: + continue + except ValueError: + pass # endpoint is not within a blueprint + + if endpoint in self.undoc_endpoints: + continue + try: + static_url_path = app.static_url_path # Flask 0.7 or higher + except AttributeError: + static_url_path = app.static_path # Flask 0.6 or under + if ('undoc-static' in self.options and endpoint == 'static' and + static_url_path + '/(path:filename)' in paths): + continue + view = app.view_functions[endpoint] + + if self.modules and view.__module__ not in self.modules: + continue + + if self.undoc_modules and view.__module__ in self.modules: + continue + + docstring = view.__doc__ or '' + if hasattr(view, 'view_class'): + meth_func = getattr(view.view_class, method.lower(), None) + if meth_func and meth_func.__doc__: + docstring = meth_func.__doc__ + if not isinstance(docstring, six.text_type): + analyzer = ModuleAnalyzer.for_module(view.__module__) + docstring = force_decode(docstring, analyzer.encoding) + + if not docstring and 'include-empty-docstring' not in self.options: + continue + docstring = prepare_docstring(docstring) + if qref == True: + for path in paths: + row = quickref_directive(method, path, docstring) + yield row + else: + for line in http_directive(method, paths, docstring): + yield line diff --git a/doc/sphinx/_exts/httpdomain/autohttp/flaskqref.py b/doc/sphinx/_exts/httpdomain/autohttp/flaskqref.py @@ -0,0 +1,80 @@ +""" + sphinxcontrib.autohttp.flaskqref + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The sphinx.ext.autodoc-style HTTP API quick reference + builder (from Flask) + for sphinxcontrib.httpdomain. + + :copyright: Copyright 2011 by Hong Minhee + :license: BSD, see LICENSE for details. + +""" + +from docutils import nodes +from docutils.statemachine import ViewList + +from sphinxcontrib import httpdomain +from sphinx.util.nodes import nested_parse_with_titles + +from .flask import AutoflaskBase + + +class QuickReferenceFlaskDirective(AutoflaskBase): + + + header = [ '', + '.. list-table::', + ' :widths: 20 45 35', + ' :header-rows: 1', + '', + ' * - Resource', + ' - Operation', + ' - Description' + ] + + def run(self): + node = nodes.section() + node.document = self.state.document + result = ViewList() + for line in QuickReferenceFlaskDirective.header: + result.append(line, '<qrefflask>') + table={} + table_sorted_names=[] + + for table_row in self.make_rst(qref=True): + name = table_row['name'] + if table.get(name) is None: + table[name]=[] + table[name].append(table_row) + if name not in table_sorted_names: + table_sorted_names.append(name) + + table_sorted_names.sort() + + for name in table_sorted_names: + # Keep table display clean by not repeating duplicate + # resource names and descriptions + display_name = name + previous_description=None + for row in table[name]: + result.append(' * - %s' % display_name, '<qrefflask>') + display_name ="" + result.append(row['operation'], '<qrefflask>') + description = row['description'] + if previous_description is not None and previous_description == description: + description ="" + else: + previous_description = description + + result.append(' - %s' % description, '<qrefflask>') + + result.append('', '<qrefflask>') + nested_parse_with_titles(self.state, result, node) + return node.children + +def setup(app): + if 'http' not in app.domains: + httpdomain.setup(app) + app.add_directive('qrefflask', QuickReferenceFlaskDirective) + diff --git a/doc/sphinx/_exts/httpdomain/autohttp/tornado.py b/doc/sphinx/_exts/httpdomain/autohttp/tornado.py @@ -0,0 +1,128 @@ +""" + sphinxcontrib.autohttp.tornado + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The sphinx.ext.autodoc-style HTTP API reference builder (from Tornado) + for sphinxcontrib.httpdomain. + + :copyright: Copyright 2013 by Rodrigo Machado + :license: BSD, see LICENSE for details. + +""" + +import inspect +import re +import six + +from docutils import nodes +from docutils.parsers.rst import directives +from docutils.statemachine import ViewList + +from sphinx.util import force_decode +from sphinx.util.compat import Directive +from sphinx.util.nodes import nested_parse_with_titles +from sphinx.util.docstrings import prepare_docstring +from sphinx.pycode import ModuleAnalyzer + +from sphinxcontrib import httpdomain +from sphinxcontrib.autohttp.common import http_directive, import_object + + +def translate_tornado_rule(app, rule): + buf = six.StringIO() + for name, filter, conf in app.router.parse_rule(rule): + if filter: + buf.write('(') + buf.write(name) + if filter != app.router.default_filter or conf: + buf.write(':') + buf.write(filter) + if conf: + buf.write(':') + buf.write(conf) + buf.write(')') + else: + buf.write(name) + return buf.getvalue() + + +def get_routes(app): + for spec in app.handlers[0][1]: + handler = spec.handler_class + doc_methods = list(handler.SUPPORTED_METHODS) + if 'HEAD' in doc_methods: + doc_methods.remove('HEAD') + if 'OPTIONS' in doc_methods: + doc_methods.remove('OPTIONS') + + for method in doc_methods: + maybe_method = getattr(handler, method.lower(), None) + if (inspect.isfunction(maybe_method) or + inspect.ismethod(maybe_method)): + yield method.lower(), spec.regex.pattern, handler + + +def normalize_path(path): + if path.endswith('$'): + path = path[:-1] + return path + + +class AutoTornadoDirective(Directive): + + has_content = True + required_arguments = 1 + option_spec = {'endpoints': directives.unchanged, + 'undoc-endpoints': directives.unchanged, + 'include-empty-docstring': directives.unchanged} + + @property + def endpoints(self): + endpoints = self.options.get('endpoints', None) + if not endpoints: + return None + return frozenset(re.split(r'\s*,\s*', endpoints)) + + @property + def undoc_endpoints(self): + undoc_endpoints = self.options.get('undoc-endpoints', None) + if not undoc_endpoints: + return frozenset() + return frozenset(re.split(r'\s*,\s*', undoc_endpoints)) + + def make_rst(self): + app = import_object(self.arguments[0]) + for method, path, handler in get_routes(app): + class_name = handler.__name__ + method_name = getattr(handler, method).__name__ + endpoint = '.'.join((class_name, method_name)) + + if self.endpoints and endpoint not in self.endpoints: + continue + if endpoint in self.undoc_endpoints: + continue + + docstring = getattr(handler, method).__doc__ or '' + #if not isinstance(docstring, unicode): + # analyzer = ModuleAnalyzer.for_module(view.__module__) + # docstring = force_decode(docstring, analyzer.encoding) + if not docstring and 'include-empty-docstring' not in self.options: + continue + docstring = prepare_docstring(docstring) + for line in http_directive(method, normalize_path(path), docstring): + yield line + + def run(self): + node = nodes.section() + node.document = self.state.document + result = ViewList() + for line in self.make_rst(): + result.append(line, '<autotornado>') + nested_parse_with_titles(self.state, result, node) + return node.children + + +def setup(app): + if 'http' not in app.domains: + httpdomain.setup(app) + app.add_directive('autotornado', AutoTornadoDirective) diff --git a/doc/sphinx/_exts/httpdomain/httpdomain.py b/doc/sphinx/_exts/httpdomain/httpdomain.py @@ -0,0 +1,773 @@ +""" + sphinxcontrib.httpdomain + ~~~~~~~~~~~~~~~~~~~~~~~~ + + The HTTP domain for documenting RESTful HTTP APIs. + + :copyright: Copyright 2011 by Hong Minhee + :license: BSD, see LICENSE for details. + +""" + +import re + +from docutils import nodes + +from pygments.lexer import RegexLexer, bygroups +from pygments.lexers import get_lexer_by_name +from pygments.token import Literal, Text, Operator, Keyword, Name, Number +from pygments.util import ClassNotFound + +from sphinx import addnodes +from sphinx.roles import XRefRole +from sphinx.domains import Domain, ObjType, Index +from sphinx.directives import ObjectDescription, directives +from sphinx.util.nodes import make_refnode +from sphinx.util.docfields import GroupedField, TypedField + +# The env.get_doctree() lookup results in a pickle.load() call which is +# expensive enough to dominate the runtime entirely when the number of endpoints +# and references is large enough. The doctrees are generated during the read- +# phase and we can cache their lookup during the write-phase significantly +# improving performance. +# Currently sphinxcontrib-httpdomain does not declare to support parallel read +# support (parallel_read_safe is the default False) so we can simply use a +# module global to hold the cache. +_doctree_cache = {} + + +class DocRef(object): + """Represents a reference to an abstract specification.""" + + def __init__(self, base_url, anchor, section): + self.base_url = base_url + self.anchor = anchor + self.section = section + + def __repr__(self): + """Returns the URL onto related specification section for the related + object.""" + return '{0}#{1}{2}'.format(self.base_url, self.anchor, self.section) + + +class RFC2616Ref(DocRef): + """Represents a reference to RFC2616. + In 2014, RFC2616 was replaced by multiple RFCs (7230-7237).""" + + def __init__(self, section): + url = 'http://www.w3.org/Protocols/rfc2616/rfc2616-sec{0:d}.html' + url = url.format(int(section)) + super(RFC2616Ref, self).__init__(url, 'sec', section) + + +class IETFRef(DocRef): + """Represents a reference to the specific IETF RFC.""" + + def __init__(self, rfc, section): + url = 'https://tools.ietf.org/html/rfc{0:d}'.format(rfc) + super(IETFRef, self).__init__(url, 'section-', section) + + +class EventSourceRef(DocRef): + + def __init__(self, section): + url = 'http://www.w3.org/TR/eventsource/' + super(EventSourceRef, self).__init__(url, section, '') + + +class CORSRef(DocRef): + """Represents a reference to W3 Cross-Origin Resource Sharing recommendation.""" + + def __init__(self, name, type): + url = 'http://www.w3.org/TR/cors/' + super(CORSRef, self).__init__(url, name, '-' + type) + + +#: Mapping from lowercase HTTP method name to :class:`DocRef` object which +#: maintains the URL which points to the section of the RFC which defines that +#: HTTP method. +METHOD_REFS = { + 'patch': IETFRef(5789, 2), + 'options': IETFRef(7231, '4.3.7'), + 'get': IETFRef(7231, '4.3.1'), + 'head': IETFRef(7231, '4.3.2'), + 'post': IETFRef(7231, '4.3.3'), + 'put': IETFRef(7231, '4.3.4'), + 'delete': IETFRef(7231, '4.3.5'), + 'trace': IETFRef(7231, '4.3.8'), + 'connect': IETFRef(7231, '4.3.6'), + 'copy': IETFRef(2518, 8.8), + 'any': '' +} + + +#: Mapping from HTTP header name to :class:`DocRef` object which +#: maintains the URL which points to the related section of the RFC. +HEADER_REFS = { + 'Accept': IETFRef(7231, '5.3.2'), + 'Accept-Charset': IETFRef(7231, '5.3.3'), + 'Accept-Encoding': IETFRef(7231, '5.3.4'), + 'Accept-Language': IETFRef(7231, '5.3.5'), + 'Accept-Ranges': IETFRef(7233, 2.3), + 'Age': IETFRef(7234, 5.1), + 'Allow': IETFRef(7231, '7.4.1'), + 'Authorization': IETFRef(7235, 4.2), + 'Cache-Control': IETFRef(7234, 5.2), + 'Connection': IETFRef(7230, 6.1), + 'Content-Encoding': IETFRef(7231, '3.1.2.2'), + 'Content-Language': IETFRef(7231, '3.1.3.2'), + 'Content-Length': IETFRef(7230, '3.3.2'), + 'Content-Location': IETFRef(7231, '3.1.4.2'), + 'Content-MD5': RFC2616Ref(14.15), # removed + 'Content-Range': IETFRef(7233, 4.2), + 'Content-Type': IETFRef(7231, '3.1.1.5'), + 'Cookie': IETFRef(2109, '4.3.4'), # also RFC6265 section 5.4 + 'Date': IETFRef(7231, '7.1.1.2'), + 'Destination': IETFRef(2518, 9.3), + 'ETag': IETFRef(7232, 2.3), + 'Expect': IETFRef(7231, '5.1.1'), + 'Expires': IETFRef(7234, 5.3), + 'From': IETFRef(7231, '5.5.2'), + 'Host': IETFRef(7230, 5.4), + 'If-Match': IETFRef(7232, 3.1), + 'If-Modified-Since': IETFRef(7232, 3.3), + 'If-None-Match': IETFRef(7232, 3.2), + 'If-Range': IETFRef(7233, 3.2), + 'If-Unmodified-Since': IETFRef(7232, 3.4), + 'Last-Event-ID': EventSourceRef('last-event-id'), + 'Last-Modified': IETFRef(7232, 2.2), + 'Link': IETFRef(5988, '5'), + 'Location': IETFRef(7231, '7.1.2'), + 'Max-Forwards': IETFRef(7231, '5.1.2'), + 'Pragma': IETFRef(7234, 5.4), + 'Proxy-Authenticate': IETFRef(7235, 4.3), + 'Proxy-Authorization': IETFRef(7235, 4.4), + 'Range': IETFRef(7233, 3.1), + 'Referer': IETFRef(7231, '5.5.2'), + 'Retry-After': IETFRef(7231, '7.1.3'), + 'Server': IETFRef(7231, '7.4.2'), + 'Set-Cookie': IETFRef(2109, '4.2.2'), + 'TE': IETFRef(7230, 4.3), + 'Trailer': IETFRef(7230, 4.4), + 'Transfer-Encoding': IETFRef(7230, '3.3.1'), + 'Upgrade': IETFRef(7230, 6.7), + 'User-Agent': IETFRef(7231, '5.5.3'), + 'Vary': IETFRef(7231, '7.1.4'), + 'Via': IETFRef(7230, '5.7.1'), + 'Warning': IETFRef(7234, 5.5), + 'WWW-Authenticate': IETFRef(7235, 4.1), + 'Access-Control-Allow-Origin': CORSRef('access-control-allow-origin', + 'response-header'), + 'Access-Control-Allow-Credentials': CORSRef('access-control-allow-credentials', + 'response-header'), + 'Access-Control-Expose-Headers': CORSRef('access-control-expose-headers', + 'response-header'), + 'Access-Control-Max-Age': CORSRef('access-control-max-age', + 'response-header'), + 'Access-Control-Allow-Methods': CORSRef('access-control-allow-methods', + 'response-header'), + 'Access-Control-Allow-Headers': CORSRef('access-control-allow-headers', + 'response-header'), + 'Origin': CORSRef('origin', 'request-header'), + 'Access-Control-Request-Method': CORSRef('access-control-request-method', + 'response-header'), + 'Access-Control-Request-Headers': CORSRef('access-control-request-headers', + 'response-header'), +} + + +HTTP_STATUS_CODES = { + 100: 'Continue', + 101: 'Switching Protocols', + 102: 'Processing', + 200: 'OK', + 201: 'Created', + 202: 'Accepted', + 203: 'Non Authoritative Information', + 204: 'No Content', + 205: 'Reset Content', + 206: 'Partial Content', + 207: 'Multi Status', + 226: 'IM Used', # see RFC 3229 + 300: 'Multiple Choices', + 301: 'Moved Permanently', + 302: 'Found', + 303: 'See Other', + 304: 'Not Modified', + 305: 'Use Proxy', + 307: 'Temporary Redirect', + 308: 'Permanent Redirect', + 400: 'Bad Request', + 401: 'Unauthorized', + 402: 'Payment Required', # unused + 403: 'Forbidden', + 404: 'Not Found', + 405: 'Method Not Allowed', + 406: 'Not Acceptable', + 407: 'Proxy Authentication Required', + 408: 'Request Timeout', + 409: 'Conflict', + 410: 'Gone', + 411: 'Length Required', + 412: 'Precondition Failed', + 413: 'Request Entity Too Large', + 414: 'Request URI Too Long', + 415: 'Unsupported Media Type', + 416: 'Requested Range Not Satisfiable', + 417: 'Expectation Failed', + 418: "I'm a teapot", # see RFC 2324 + 422: 'Unprocessable Entity', + 423: 'Locked', + 424: 'Failed Dependency', + 425: 'Too Early', # RFC 8470 + 426: 'Upgrade Required', + 429: 'Too Many Requests', + 449: 'Retry With', # proprietary MS extension + 451: 'Unavailable For Legal Reasons', + 500: 'Internal Server Error', + 501: 'Not Implemented', + 502: 'Bad Gateway', + 503: 'Service Unavailable', + 504: 'Gateway Timeout', + 505: 'HTTP Version Not Supported', + 507: 'Insufficient Storage', + 510: 'Not Extended' +} + +WEBDAV_STATUS_CODES = [207, 422, 423, 424, 507] + +http_sig_param_re = re.compile(r'\((?:(?P<type>[^:)]+):)?(?P<name>[\w_]+)\)', + re.VERBOSE) + + +def sort_by_method(entries): + def cmp(item): + order = ['HEAD', 'GET', 'POST', 'PUT', 'DELETE', 'PATCH', + 'OPTIONS', 'TRACE', 'CONNECT', 'COPY', 'ANY'] + method = item[0].split(' ', 1)[0] + if method in order: + return order.index(method) + return 100 + return sorted(entries, key=cmp) + + +def http_resource_anchor(method, path): + path = re.sub(r'[{}]', '', re.sub(r'[<>:/]', '-', path)) + return method.lower() + '-' + path + + +class HTTPResource(ObjectDescription): + + doc_field_types = [ + TypedField('parameter', label='Parameters', + names=('param', 'parameter', 'arg', 'argument'), + typerolename='obj', typenames=('paramtype', 'type')), + TypedField('jsonparameter', label='JSON Parameters', + names=('jsonparameter', 'jsonparam', 'json'), + typerolename='obj', typenames=('jsonparamtype', 'jsontype')), + TypedField('requestjsonobject', label='Request JSON Object', + names=('reqjsonobj', 'reqjson', '<jsonobj', '<json'), + typerolename='obj', typenames=('reqjsonobj', '<jsonobj')), + TypedField('requestjsonarray', label='Request JSON Array of Objects', + names=('reqjsonarr', '<jsonarr'), + typerolename='obj', + typenames=('reqjsonarrtype', '<jsonarrtype')), + TypedField('responsejsonobject', label='Response JSON Object', + names=('resjsonobj', 'resjson', '>jsonobj', '>json'), + typerolename='obj', typenames=('resjsonobj', '>jsonobj')), + TypedField('responsejsonarray', label='Response JSON Array of Objects', + names=('resjsonarr', '>jsonarr'), + typerolename='obj', + typenames=('resjsonarrtype', '>jsonarrtype')), + TypedField('queryparameter', label='Query Parameters', + names=('queryparameter', 'queryparam', 'qparam', 'query'), + typerolename='obj', + typenames=('queryparamtype', 'querytype', 'qtype')), + GroupedField('formparameter', label='Form Parameters', + names=('formparameter', 'formparam', 'fparam', 'form')), + GroupedField('requestheader', label='Request Headers', + rolename='header', + names=('<header', 'reqheader', 'requestheader')), + GroupedField('responseheader', label='Response Headers', + rolename='header', + names=('>header', 'resheader', 'responseheader')), + GroupedField('statuscode', label='Status Codes', + rolename='statuscode', + names=('statuscode', 'status', 'code')) + ] + + option_spec = { + 'deprecated': directives.flag, + 'noindex': directives.flag, + 'synopsis': lambda x: x, + } + + method = NotImplemented + + def handle_signature(self, sig, signode): + method = self.method.upper() + ' ' + signode += addnodes.desc_name(method, method) + offset = 0 + path = None + for match in http_sig_param_re.finditer(sig): + path = sig[offset:match.start()] + signode += addnodes.desc_name(path, path) + params = addnodes.desc_parameterlist() + typ = match.group('type') + if typ: + typ += ': ' + params += addnodes.desc_annotation(typ, typ) + name = match.group('name') + params += addnodes.desc_parameter(name, name) + signode += params + offset = match.end() + if offset < len(sig): + path = sig[offset:len(sig)] + signode += addnodes.desc_name(path, path) + assert path is not None, 'no matches for sig: %s' % sig + fullname = self.method.upper() + ' ' + path + signode['method'] = self.method + signode['path'] = sig + signode['fullname'] = fullname + return (fullname, self.method, sig) + + def needs_arglist(self): + return False + + def add_target_and_index(self, name_cls, sig, signode): + signode['ids'].append(http_resource_anchor(*name_cls[1:])) + if 'noindex' not in self.options: + self.env.domaindata['http'][self.method][sig] = ( + self.env.docname, + self.options.get('synopsis', ''), + 'deprecated' in self.options) + + def get_index_text(self, modname, name): + return '' + + +class HTTPOptions(HTTPResource): + + method = 'options' + + +class HTTPHead(HTTPResource): + + method = 'head' + + +class HTTPPatch(HTTPResource): + + method = 'patch' + + +class HTTPPost(HTTPResource): + + method = 'post' + + +class HTTPGet(HTTPResource): + + method = 'get' + + +class HTTPPut(HTTPResource): + + method = 'put' + + +class HTTPDelete(HTTPResource): + + method = 'delete' + + +class HTTPTrace(HTTPResource): + + method = 'trace' + + +class HTTPConnect(HTTPResource): + + method = 'connect' + + +class HTTPCopy(HTTPResource): + + method = 'copy' + + +class HTTPAny(HTTPResource): + + method = 'any' + + +class HTTPXRefRole(XRefRole): + + def __init__(self, method, **kwargs): + XRefRole.__init__(self, **kwargs) + self.method = method + + def process_link(self, env, refnode, has_explicit_title, title, target): + if not has_explicit_title: + title = self.method.upper() + ' ' + title + return title, target + + +class HTTPXRefMethodRole(XRefRole): + + def result_nodes(self, document, env, node, is_ref): + method = node[0][0].lower() + rawsource = node[0].rawsource + config = env.domains['http'].env.config + if method not in METHOD_REFS: + if not config['http_strict_mode']: + return [nodes.emphasis(method, method)], [] + reporter = document.reporter + msg = reporter.error('%s is not valid HTTP method' % method, + line=node.line) + prb = nodes.problematic(method, method) + return [prb], [msg] + url = str(METHOD_REFS[method]) + if not url: + return [nodes.emphasis(method, method)], [] + node = nodes.reference(rawsource, method.upper(), refuri=url) + return [node], [] + + +class HTTPXRefStatusRole(XRefRole): + + def result_nodes(self, document, env, node, is_ref): + def get_code_status(text): + if text.isdigit(): + code = int(text) + return code, HTTP_STATUS_CODES.get(code) + else: + try: + code, status = re.split(r'\s', text.strip(), 1) + code = int(code) + except ValueError: + return None, None + known_status = HTTP_STATUS_CODES.get(code) + if known_status is None: + return code, None + elif known_status.lower() != status.lower(): + return code, None + else: + return code, status + + def report_unknown_code(): + if not config['http_strict_mode']: + return [nodes.emphasis(text, text)], [] + reporter = document.reporter + msg = reporter.error('%d is unknown HTTP status code' % code, + line=node.line) + prb = nodes.problematic(text, text) + return [prb], [msg] + + def report_invalid_code(): + if not config['http_strict_mode']: + return [nodes.emphasis(text, text)], [] + reporter = document.reporter + msg = reporter.error( + 'HTTP status code must be an integer (e.g. `200`) or ' + 'start with an integer (e.g. `200 OK`); %r is invalid' % + text, + line=node.line + ) + prb = nodes.problematic(text, text) + return [prb], [msg] + + text = node[0][0] + rawsource = node[0].rawsource + config = env.domains['http'].env.config + + code, status = get_code_status(text) + if code is None: + return report_invalid_code() + elif status is None: + return report_unknown_code() + elif code == 226: + url = 'http://www.ietf.org/rfc/rfc3229.txt' + elif code == 418: + url = 'http://www.ietf.org/rfc/rfc2324.txt' + elif code == 429: + url = 'http://tools.ietf.org/html/rfc6585#section-4' + elif code == 449: + url = 'http://msdn.microsoft.com/en-us/library/dd891478(v=prot.10).aspx' + elif code == 451: + url = 'http://www.ietf.org/rfc/rfc7725.txt' + elif code in WEBDAV_STATUS_CODES: + url = 'http://tools.ietf.org/html/rfc4918#section-11.%d' % (WEBDAV_STATUS_CODES.index(code) + 1) + elif code in HTTP_STATUS_CODES: + url = 'http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html' \ + '#sec10.' + ('%d.%d' % (code // 100, 1 + code % 100)) + else: + url = '' + node = nodes.reference(rawsource, '%d %s' % (code, status), refuri=url) + return [node], [] + + +class HTTPXRefHeaderRole(XRefRole): + + def result_nodes(self, document, env, node, is_ref): + header = node[0][0] + rawsource = node[0].rawsource + if header not in HEADER_REFS: + _header = '-'.join(map(lambda i: i.title(), header.split('-'))) + if _header not in HEADER_REFS: + return [nodes.emphasis(header, header)], [] + url = str(HEADER_REFS[header]) + node = nodes.reference(rawsource, header, refuri=url) + return [node], [] + + +class HTTPIndex(Index): + + name = 'routingtable' + localname = 'HTTP Routing Table' + shortname = 'routing table' + + def __init__(self, *args, **kwargs): + super(HTTPIndex, self).__init__(*args, **kwargs) + + self.ignore = [ + [l for l in x.split('/') if l] + for x in self.domain.env.config['http_index_ignore_prefixes']] + self.ignore.sort(reverse=True) + + # During HTML generation these values pick from class, + # not from instance so we have a little hack the system + cls = self.__class__ + cls.shortname = self.domain.env.config['http_index_shortname'] + cls.localname = self.domain.env.config['http_index_localname'] + + def grouping_prefix(self, path): + letters = [x for x in path.split('/') if x] + for prefix in self.ignore: + if letters[:len(prefix)] == prefix: + return '/' + '/'.join(letters[:len(prefix) + 1]) + return '/%s' % (letters[0] if letters else '',) + + def generate(self, docnames=None): + content = {} + items = ((method, path, info) + for method, routes in self.domain.routes.items() + for path, info in routes.items()) + items = sorted(items, key=lambda item: item[1]) + for method, path, info in items: + entries = content.setdefault(self.grouping_prefix(path), []) + entries.append([ + method.upper() + ' ' + path, 0, info[0], + http_resource_anchor(method, path), + '', 'Deprecated' if info[2] else '', info[1] + ]) + items = sorted( + (path, sort_by_method(entries)) + for path, entries in content.items() + ) + return (items, True) + + +class HTTPDomain(Domain): + """HTTP domain.""" + + name = 'http' + label = 'HTTP' + + object_types = { + 'options': ObjType('options', 'options', 'obj'), + 'head': ObjType('head', 'head', 'obj'), + 'post': ObjType('post', 'post', 'obj'), + 'get': ObjType('get', 'get', 'obj'), + 'put': ObjType('put', 'put', 'obj'), + 'patch': ObjType('patch', 'patch', 'obj'), + 'delete': ObjType('delete', 'delete', 'obj'), + 'trace': ObjType('trace', 'trace', 'obj'), + 'connect': ObjType('connect', 'connect', 'obj'), + 'copy': ObjType('copy', 'copy', 'obj'), + 'any': ObjType('any', 'any', 'obj') + } + + directives = { + 'options': HTTPOptions, + 'head': HTTPHead, + 'post': HTTPPost, + 'get': HTTPGet, + 'put': HTTPPut, + 'patch': HTTPPatch, + 'delete': HTTPDelete, + 'trace': HTTPTrace, + 'connect': HTTPConnect, + 'copy': HTTPCopy, + 'any': HTTPAny + } + + roles = { + 'options': HTTPXRefRole('options'), + 'head': HTTPXRefRole('head'), + 'post': HTTPXRefRole('post'), + 'get': HTTPXRefRole('get'), + 'put': HTTPXRefRole('put'), + 'patch': HTTPXRefRole('patch'), + 'delete': HTTPXRefRole('delete'), + 'trace': HTTPXRefRole('trace'), + 'connect': HTTPXRefRole('connect'), + 'copy': HTTPXRefRole('copy'), + 'any': HTTPXRefRole('any'), + 'statuscode': HTTPXRefStatusRole(), + 'method': HTTPXRefMethodRole(), + 'header': HTTPXRefHeaderRole() + } + + initial_data = { + 'options': {}, # path: (docname, synopsis) + 'head': {}, + 'post': {}, + 'get': {}, + 'put': {}, + 'patch': {}, + 'delete': {}, + 'trace': {}, + 'connect': {}, + 'copy': {}, + 'any': {} + } + + indices = [] + + @property + def routes(self): + return dict((key, self.data[key]) for key in self.object_types) + + def clear_doc(self, docname): + for typ, routes in self.routes.items(): + for path, info in list(routes.items()): + if info[0] == docname: + del routes[path] + + def resolve_xref(self, env, fromdocname, builder, typ, target, + node, contnode): + try: + info = self.data[str(typ)][target] + except KeyError: + text = contnode.rawsource + role = self.roles.get(typ) + if role is None: + return None + + if fromdocname not in _doctree_cache: + _doctree_cache[fromdocname] = env.get_doctree(fromdocname) + doctree = _doctree_cache[fromdocname] + + resnode = role.result_nodes(doctree, env, node, None)[0][0] + if isinstance(resnode, addnodes.pending_xref): + text = node[0][0] + reporter = doctree.reporter + reporter.warning('Cannot resolve reference to %r' % text, + line=node.line) + return None + return resnode + else: + anchor = http_resource_anchor(typ, target) + title = typ.upper() + ' ' + target + return make_refnode(builder, fromdocname, info[0], anchor, + contnode, title) + + def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): + """Resolve the pending_xref *node* with the given *target*. + + The reference comes from an "any" or similar role, which means that Sphinx + don't know the type. + + For now sphinxcontrib-httpdomain doesn't resolve any xref nodes. + + :return: + list of tuples ``('domain:role', newnode)``, where ``'domain:role'`` + is the name of a role that could have created the same reference, + """ + return [] + + def get_objects(self): + for method, routes in self.routes.items(): + for path, info in routes.items(): + anchor = http_resource_anchor(method, path) + yield (path, path, method, info[0], anchor, 1) + + +class HTTPLexer(RegexLexer): + """Lexer for HTTP sessions.""" + + name = 'HTTP' + aliases = ['http'] + + flags = re.DOTALL + + def header_callback(self, match): + if match.group(1).lower() == 'content-type': + content_type = match.group(5).strip() + if ';' in content_type: + content_type = content_type[:content_type.find(';')].strip() + self.content_type = content_type + yield match.start(1), Name.Attribute, match.group(1) + yield match.start(2), Text, match.group(2) + yield match.start(3), Operator, match.group(3) + yield match.start(4), Text, match.group(4) + yield match.start(5), Literal, match.group(5) + yield match.start(6), Text, match.group(6) + + def continuous_header_callback(self, match): + yield match.start(1), Text, match.group(1) + yield match.start(2), Literal, match.group(2) + yield match.start(3), Text, match.group(3) + + def content_callback(self, match): + content_type = getattr(self, 'content_type', None) + content = match.group() + offset = match.start() + if content_type: + from pygments.lexers import get_lexer_for_mimetype + try: + lexer = get_lexer_for_mimetype(content_type) + except ClassNotFound: + pass + else: + for idx, token, value in lexer.get_tokens_unprocessed(content): + yield offset + idx, token, value + return + yield offset, Text, content + + tokens = { + 'root': [ + (r'(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS|TRACE|COPY)( +)([^ ]+)( +)' + r'(HTTPS?)(/)(1\.[01])(\r?\n|$)', + bygroups(Name.Function, Text, Name.Namespace, Text, + Keyword.Reserved, Operator, Number, Text), + 'headers'), + (r'(HTTPS?)(/)(1\.[01])( +)(\d{3})( +)([^\r\n]+)(\r?\n|$)', + bygroups(Keyword.Reserved, Operator, Number, Text, Number, + Text, Name.Exception, Text), + 'headers'), + ], + 'headers': [ + (r'([^\s:]+)( *)(:)( *)([^\r\n]+)(\r?\n|$)', header_callback), + (r'([\t ]+)([^\r\n]+)(\r?\n|$)', continuous_header_callback), + (r'\r?\n', Text, 'content') + ], + 'content': [ + (r'.+', content_callback) + ] + } + + +def setup(app): + app.add_domain(HTTPDomain) + + try: + get_lexer_by_name('http') + except ClassNotFound: + app.add_lexer('http', HTTPLexer()) + app.add_config_value('http_index_ignore_prefixes', [], None) + app.add_config_value('http_index_shortname', 'routing table', True) + app.add_config_value('http_index_localname', 'HTTP Routing Table', True) + app.add_config_value('http_strict_mode', True, None) + app.add_config_value('http_headers_ignore_prefixes', ['X-'], None) diff --git a/doc/sphinx/_exts/taler_sphinx_theme/__init__.py b/doc/sphinx/_exts/taler_sphinx_theme/__init__.py @@ -0,0 +1,166 @@ +"""Sphinx Guzzle theme.""" + +import os +from os import path +import xml.etree.ElementTree as ET + +from docutils import nodes +from sphinx.locale import admonitionlabels +from sphinx.writers.html import HTMLTranslator as SphinxHTMLTranslator + +from pygments.style import Style +from pygments.token import Keyword, Name, Comment, String, Error, \ + Number, Operator, Generic, Whitespace, Punctuation, Other, Literal + + +def setup(app): + """Setup conntects events to the sitemap builder""" + app.connect('html-page-context', add_html_link) + app.connect('build-finished', create_sitemap) + app.set_translator('html', MyHTMLTranslator) + app.set_translator('html-linked', MyHTMLTranslator) + app.sitemap_links = [] + app.add_html_theme('taler_sphinx_theme', path.abspath(path.dirname(__file__) + "/guzzle_sphinx_theme")) + + +def add_html_link(app, pagename, templatename, context, doctree): + """As each page is built, collect page names for the sitemap""" + base_url = app.config['html_theme_options'].get('base_url', '') + if base_url: + app.sitemap_links.append(base_url + pagename + ".html") + + +def create_sitemap(app, exception): + """Generates the sitemap.xml from the collected HTML page links""" + if (not app.config['html_theme_options'].get('base_url', '') or + exception is not None or + not app.sitemap_links): + return + + filename = app.outdir + "/sitemap.xml" + print("Generating sitemap.xml in %s" % filename) + + root = ET.Element("urlset") + root.set("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9") + + for link in app.sitemap_links: + url = ET.SubElement(root, "url") + ET.SubElement(url, "loc").text = link + + ET.ElementTree(root).write(filename) + + +def html_theme_path(): + return [os.path.dirname(os.path.abspath(__file__))] + + +class MyHTMLTranslator(SphinxHTMLTranslator): + """ + Handle translating to bootstrap structure. + """ + def visit_table(self, node, name=''): + """ + Override docutils default table formatter to not include a border + and to use Bootstrap CSS + See: http://sourceforge.net/p/docutils/code/HEAD/tree/trunk/docutils/docutils/writers/html4css1/__init__.py#l1550 + """ + self.context.append(self.compact_p) + self.compact_p = True + classes = 'table table-bordered ' + self.settings.table_style + classes = classes.strip() + self.body.append( + self.starttag(node, 'table', CLASS=classes)) + + def depart_table(self, node): + """ + This needs overridin' too + """ + self.compact_p = self.context.pop() + self.body.append('</table>\n') + + def visit_field(self, node): + pass + + def depart_field(self, node): + pass + + def visit_field_name(self, node): + atts = {} + if self.in_docinfo: + atts['class'] = 'docinfo-name' + else: + atts['class'] = 'field-name' + self.context.append('') + self.body.append(self.starttag(node, 'dt', '', **atts)) + + def depart_field_name(self, node): + self.body.append('</dt>') + self.body.append(self.context.pop()) + + def visit_field_body(self, node): + self.body.append(self.starttag(node, 'dd', '', CLASS='field-body')) + self.set_class_on_child(node, 'first', 0) + field = node.parent + if (self.compact_field_list or + isinstance(field.parent, nodes.docinfo) or + field.parent.index(field) == len(field.parent) - 1): + # If we are in a compact list, the docinfo, or if this is + # the last field of the field list, do not add vertical + # space after last element. + self.set_class_on_child(node, 'last', -1) + + def depart_field_body(self, node): + self.body.append('</dd>\n') + + def visit_field_list(self, node): + self.context.append((self.compact_field_list, self.compact_p)) + self.compact_p = None + if 'compact' in node['classes']: + self.compact_field_list = True + elif (self.settings.compact_field_lists + and 'open' not in node['classes']): + self.compact_field_list = True + if self.compact_field_list: + for field in node: + field_body = field[-1] + assert isinstance(field_body, nodes.field_body) + children = [n for n in field_body + if not isinstance(n, nodes.Invisible)] + if not (len(children) == 0 or + len(children) == 1 and + isinstance(children[0], + (nodes.paragraph, nodes.line_block))): + self.compact_field_list = False + break + self.body.append(self.starttag(node, 'dl', frame='void', + rules='none', + CLASS='docutils field-list')) + + def depart_field_list(self, node): + self.body.append('</dl>\n') + self.compact_field_list, self.compact_p = self.context.pop() + + def visit_container(self, node): + self.body.append(self.starttag(node, 'div', CLASS='docutils')) + + def add_secnumber(self, node): + # type: (nodes.Element) -> None + if node.get('secnumber'): + numbers = list(map(str, node['secnumber'])) + if len(numbers) <= 3: + self.body.append('.'.join(numbers) + self.secnumber_suffix) + elif isinstance(node.parent, nodes.section): + if self.builder.name == 'singlehtml': + docname = self.docnames[-1] + anchorname = "%s/#%s" % (docname, node.parent['ids'][0]) + if anchorname not in self.builder.secnumbers: + anchorname = "%s/" % docname # try first heading which has no anchor + else: + anchorname = '#' + node.parent['ids'][0] + if anchorname not in self.builder.secnumbers: + anchorname = '' # try first heading which has no anchor + if self.builder.secnumbers.get(anchorname): + numbers = list(self.builder.secnumbers[anchorname]) + if len(numbers) <= 3: + self.body.append('.'.join(map(str, numbers)) + + self.secnumber_suffix) diff --git a/doc/sphinx/_exts/taler_sphinx_theme/__pycache__/__init__.cpython-310.pyc b/doc/sphinx/_exts/taler_sphinx_theme/__pycache__/__init__.cpython-310.pyc Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/comments.html b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/comments.html @@ -0,0 +1,16 @@ +{% if theme_disqus_comments_shortname %} +<div id="comments"> + <div id="disqus_thread"></div> + <script type="text/javascript"> + var disqus_shortname = '{{ theme_disqus_comments_shortname }}'; + var disqus_identifier = '{{ pagename }}'; + (function() { + var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; + dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; + (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); + })(); + </script> + <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> + <a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> +</div> +{% endif %} diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/globaltoc.html b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/globaltoc.html @@ -0,0 +1,14 @@ + +<div class="sidebar-block"> + <div class="sidebar-wrapper"> + <h2>{{ _('Table Of Contents') }}</h2> + </div> + <div class="sidebar-toc"> + {% set toctree = toctree(maxdepth=theme_globaltoc_depth|toint, collapse=theme_globaltoc_collapse|tobool, includehidden=theme_globaltoc_includehidden|tobool) %} + {% if toctree %} + {{ toctree }} + {% else %} + {{ toc }} + {% endif %} + </div> +</div> diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/layout.html b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/layout.html @@ -0,0 +1,172 @@ +{%- extends "basic/layout.html" %} + +{# Do this so that bootstrap is included before the main css file #} +{%- block htmltitle %} + <!-- Licensed under the Apache 2.0 License --> + <link rel="stylesheet" type="text/css" href="{{ pathto('_static/fonts/open-sans/stylesheet.css', 1) }}" /> + <!-- Licensed under the SIL Open Font License --> + <link rel="stylesheet" type="text/css" href="{{ pathto('_static/fonts/source-serif-pro/source-serif-pro.css', 1) }}" /> + <link rel="stylesheet" type="text/css" href="{{ pathto('_static/css/bootstrap.min.css', 1) }}" /> + <link rel="stylesheet" type="text/css" href="{{ pathto('_static/css/bootstrap-theme.min.css', 1) }}" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + {{ super() }} +{%- endblock %} + +{%- block extrahead %} + {% if theme_touch_icon %} + <link rel="apple-touch-icon" href="{{ pathto('_static/' ~ theme_touch_icon, 1) }}" /> + {% endif %} + {{ super() }} +{% endblock %} + +{# Displays the URL for the homepage if it's set or the master_doc if it is not #} +{% macro homepage() -%} + {%- if theme_homepage %} + {%- if hasdoc(theme_homepage) %} + {{ pathto(theme_homepage) }} + {%- else %} + {{ theme_homepage }} + {%- endif %} + {%- else %} + {{ pathto(master_doc) }} + {%- endif %} +{%- endmacro %} + +{# Displays the URL for the tospage if it's set or falls back to homepage macro #} +{% macro tospage() -%} + {%- if theme_tospage %} + {%- if hasdoc(theme_tospage) %} + {{ pathto(theme_tospage) }} + {%- else %} + {{ theme_tospage }} + {%- endif %} + {%- else %} + {{ homepage() }} + {%- endif %} +{%- endmacro %} + +{# Displays the URL for the projectpage if it's set or falls back to homepage macro #} +{% macro projectlink() -%} + {%- if theme_projectlink %} + {%- if hasdoc(theme_projectlink) %} + {{ pathto(theme_projectlink) }} + {%- else %} + {{ theme_projectlink }} + {%- endif %} + {%- else %} + {{ homepage() }} + {%- endif %} +{%- endmacro %} + +{# Displays the next and previous links both before and after content #} +{% macro render_relations() -%} + {% if prev or next %} + <div class="footer-relations"> + {% if prev %} + <div class="pull-left"> + <a class="btn btn-default" href="{{ prev.link|e }}" title="{{ _('previous chapter')}} (use the left arrow)">{{ prev.title }}</a> + </div> + {% endif %} + {%- if next and next.title != '&lt;no title&gt;' %} + <div class="pull-right"> + <a class="btn btn-default" href="{{ next.link|e }}" title="{{ _('next chapter')}} (use the right arrow)">{{ next.title }}</a> + </div> + {%- endif %} + </div> + <div class="clearer"></div> + {% endif %} +{%- endmacro %} + +{%- macro guzzle_sidebar() %} + <div id="left-column"> + <div class="sphinxsidebar"> + {%- if sidebars != None %} + {#- new style sidebar: explicitly include/exclude templates #} + {%- for sidebartemplate in sidebars %} + {%- include sidebartemplate %} + {%- endfor %} + {% else %} + {% include "logo-text.html" %} + {% include "globaltoc.html" %} + {% include "searchbox.html" %} + {%- endif %} + </div> + </div> +{%- endmacro %} + +{%- block content %} + + {%- if pagename == 'index' and theme_index_template %} + {% include theme_index_template %} + {%- else %} + <div class="container-wrapper"> + + <div id="mobile-toggle"> + <a href="#"><span class="glyphicon glyphicon-align-justify" aria-hidden="true"></span></a> + </div> + + {%- block sidebar1 %}{{ guzzle_sidebar() }}{% endblock %} + + {%- block document_wrapper %} + {%- block document %} + <div id="right-column"> + {% block breadcrumbs %} + <div role="navigation" aria-label="breadcrumbs navigation"> + <ol class="breadcrumb"> + <li><a href="{{ pathto(master_doc) }}">Docs</a></li> + {% for doc in parents %} + <li><a href="{{ doc.link|e }}">{{ doc.title }}</a></li> + {% endfor %} + <li>{{ title }}</li> + </ol> + </div> + {% endblock %} + <div class="document clearer body" role="main"> + {% block body %} {% endblock %} + </div> + {%- block bottom_rel_links %} + {{ render_relations() }} + {%- endblock %} + </div> + <div class="clearfix"></div> + {%- endblock %} + {%- endblock %} + + {%- block comments -%} + {% if theme_disqus_comments_shortname %} + <div class="container comment-container"> + {% include "comments.html" %} + </div> + {% endif %} + {%- endblock %} + </div> + {%- endif %} + {%- endblock %} + +{%- block footer %} +<script type="text/javascript"> + $("#mobile-toggle a").click(function () { + $("#left-column").toggle(); + }); +</script> +<script type="text/javascript" src="{{ pathto('_static/js/bootstrap.js', 1)}}"></script> +{%- block footer_wrapper %} + <div class="footer"> + &copy; Copyright {{ copyright }}. Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> +{%- endblock %} +{%- block ga %} + {%- if theme_google_analytics_account %} + <script type="text/javascript"> + var _gaq = _gaq || []; + _gaq.push(['_setAccount', '{{ theme_google_analytics_account }}']); + _gaq.push(['_trackPageview']); + (function() { + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + })(); + </script> + {%- endif %} +{%- endblock %} +{%- endblock %} diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/localtoc.html b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/localtoc.html @@ -0,0 +1,10 @@ +{%- if display_toc %} +<div class="sidebar-block"> + <div class="sidebar-wrapper"> + <h2>{{ _('Contents') }}</h2> + <div class="sidebar-localtoc"> + {{ toc }} + </div> + </div> +</div> +{%- endif %} diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/logo-text.html b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/logo-text.html @@ -0,0 +1 @@ +<a href="{{ homepage() }}" class="text-logo">{{ theme_project_nav_name or shorttitle }}</a> diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/search.html b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/search.html @@ -0,0 +1,48 @@ +{%- extends "basic/search.html" %} + +{% block body %} + <h1 id="search-documentation">{{ _('Search') }}</h1> + <div id="fallback" class="admonition warning"> + <script type="text/javascript">$('#fallback').hide();</script> + <p> + {% trans %}Please activate JavaScript to enable the search + functionality.{% endtrans %} + </p> + </div> + <p> + {% trans %}From here you can search these documents. Enter your search + words into the box below and click "search". Note that the search + function will automatically search for all of the words. Pages + containing fewer words won't appear in the result list.{% endtrans %} + </p> + + <div class="search-page-form"> + <form class="form-inline" action="{{ pathto('search') }}" method="GET" role="form"> + <div class="input-group"> + <input name="q" type="text" class="form-control" /> + <span class="input-group-btn"> + <button class="btn btn-default" type="button">{{ _('search') }}</button> + </span> + </div> + <span id="search-progress" style="padding-left: 10px"></span> + </form> + </div> + + {% if search_performed %} + <h2>{{ _('Search Results') }}</h2> + {% if not search_results %} + <p>{{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}</p> + {% endif %} + {% endif %} + <div id="search-results"> + {% if search_results %} + <ul> + {% for href, caption, context in search_results %} + <li><a href="{{ pathto(item.href) }}">{{ caption }}</a> + <div class="context">{{ context|e }}</div> + </li> + {% endfor %} + </ul> + {% endif %} + </div> +{% endblock %} diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/searchbox.html b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/searchbox.html @@ -0,0 +1,15 @@ +{%- if pagename != "search" %} +<div class="sidebar-block"> + <div class="sidebar-wrapper"> + <div id="main-search"> + <form class="form-inline" action="{{ pathto('search') }}" method="GET" role="form"> + <div class="input-group"> + <input name="q" type="text" class="form-control" placeholder="Search..."> + </div> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + </div> + </div> +</div> +{%- endif %} diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/css/bootstrap-theme.min.css b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/css/bootstrap-theme.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.1.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:active,.btn.active{background-image:none}.btn-default{background-image:-webkit-linear-gradient(top, #fff 0, #e0e0e0 100%);background-image:linear-gradient(to bottom, #fff 0, #e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#dbdbdb;text-shadow:0 1px 0 #fff;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-linear-gradient(top, #428bca 0, #2d6ca2 100%);background-image:linear-gradient(to bottom, #428bca 0, #2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-linear-gradient(top, #5cb85c 0, #419641 100%);background-image:linear-gradient(to bottom, #5cb85c 0, #419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-info{background-image:-webkit-linear-gradient(top, #5bc0de 0, #2aabd2 100%);background-image:linear-gradient(to bottom, #5bc0de 0, #2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-warning{background-image:-webkit-linear-gradient(top, #f0ad4e 0, #eb9316 100%);background-image:linear-gradient(to bottom, #f0ad4e 0, #eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-danger{background-image:-webkit-linear-gradient(top, #d9534f 0, #c12e2a 100%);background-image:linear-gradient(to bottom, #d9534f 0, #c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-image:-webkit-linear-gradient(top, #f5f5f5 0, #e8e8e8 100%);background-image:linear-gradient(to bottom, #f5f5f5 0, #e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-color:#e8e8e8}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-image:-webkit-linear-gradient(top, #428bca 0, #357ebd 100%);background-image:linear-gradient(to bottom, #428bca 0, #357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-color:#357ebd}.navbar-default{background-image:-webkit-linear-gradient(top, #fff 0, #f8f8f8 100%);background-image:linear-gradient(to bottom, #fff 0, #f8f8f8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top, #ebebeb 0, #f3f3f3 100%);background-image:linear-gradient(to bottom, #ebebeb 0, #f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.075);box-shadow:inset 0 3px 9px rgba(0,0,0,0.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,0.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top, #3c3c3c 0, #222 100%);background-image:linear-gradient(to bottom, #3c3c3c 0, #222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top, #222 0, #282828 100%);background-image:linear-gradient(to bottom, #222 0, #282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.25);box-shadow:inset 0 3px 9px rgba(0,0,0,0.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05)}.alert-success{background-image:-webkit-linear-gradient(top, #dff0d8 0, #c8e5bc 100%);background-image:linear-gradient(to bottom, #dff0d8 0, #c8e5bc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top, #d9edf7 0, #b9def0 100%);background-image:linear-gradient(to bottom, #d9edf7 0, #b9def0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top, #fcf8e3 0, #f8efc0 100%);background-image:linear-gradient(to bottom, #fcf8e3 0, #f8efc0 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top, #f2dede 0, #e7c3c3 100%);background-image:linear-gradient(to bottom, #f2dede 0, #e7c3c3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top, #ebebeb 0, #f5f5f5 100%);background-image:linear-gradient(to bottom, #ebebeb 0, #f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0)}.progress-bar{background-image:-webkit-linear-gradient(top, #428bca 0, #3071a9 100%);background-image:linear-gradient(to bottom, #428bca 0, #3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0)}.progress-bar-success{background-image:-webkit-linear-gradient(top, #5cb85c 0, #449d44 100%);background-image:linear-gradient(to bottom, #5cb85c 0, #449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0)}.progress-bar-info{background-image:-webkit-linear-gradient(top, #5bc0de 0, #31b0d5 100%);background-image:linear-gradient(to bottom, #5bc0de 0, #31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0)}.progress-bar-warning{background-image:-webkit-linear-gradient(top, #f0ad4e 0, #ec971f 100%);background-image:linear-gradient(to bottom, #f0ad4e 0, #ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0)}.progress-bar-danger{background-image:-webkit-linear-gradient(top, #d9534f 0, #c9302c 100%);background-image:linear-gradient(to bottom, #d9534f 0, #c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top, #428bca 0, #3278b3 100%);background-image:linear-gradient(to bottom, #428bca 0, #3278b3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);border-color:#3278b3}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top, #f5f5f5 0, #e8e8e8 100%);background-image:linear-gradient(to bottom, #f5f5f5 0, #e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top, #428bca 0, #357ebd 100%);background-image:linear-gradient(to bottom, #428bca 0, #357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top, #dff0d8 0, #d0e9c6 100%);background-image:linear-gradient(to bottom, #dff0d8 0, #d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top, #d9edf7 0, #c4e3f3 100%);background-image:linear-gradient(to bottom, #d9edf7 0, #c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top, #fcf8e3 0, #faf2cc 100%);background-image:linear-gradient(to bottom, #fcf8e3 0, #faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top, #f2dede 0, #ebcccc 100%);background-image:linear-gradient(to bottom, #f2dede 0, #ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0)}.well{background-image:-webkit-linear-gradient(top, #e8e8e8 0, #f5f5f5 100%);background-image:linear-gradient(to bottom, #e8e8e8 0, #f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1)} +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/css/bootstrap.min.css b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/css/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.1.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +/*! normalize.css v3.0.0 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff !important}.navbar{display:none}.table td,.table th{background-color:#fff !important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#999}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-muted{color:#999}.text-primary{color:#428bca}a.text-primary:hover{color:#3071a9}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}.list-inline>li:first-child{padding-left:0}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.428571429;color:#999}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;white-space:nowrap;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25)}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;word-break:break-all;word-wrap:break-word;color:#333;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{position:static;float:none;display:table-column}table td[class*="col-"],table th[class*="col-"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}@media (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;overflow-x:scroll;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}input[type="range"]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s, box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s, box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6)}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type="date"]{line-height:34px}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;margin-top:10px;margin-bottom:10px;padding-left:20px}.radio label,.checkbox label{display:inline;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:normal;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg,select[multiple].input-lg{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.has-feedback .form-control-feedback{position:absolute;top:25px;right:0;display:block;width:34px;height:34px;line-height:34px;text-align:center}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;border-color:#8a6d3b;background-color:#fcf8e3}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.has-error .form-control-feedback{color:#a94442}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;padding-left:0;vertical-align:middle}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}.form-horizontal .form-control-static{padding-top:7px}@media (min-width:768px){.form-horizontal .control-label{text-align:right}}.form-horizontal .has-feedback .form-control-feedback{top:0;right:15px}.btn{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.428571429;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#428bca;font-weight:normal;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%;padding-left:0;padding-right:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#262626;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#428bca}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:none}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:4px;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*="col-"]{float:none;padding-left:0;padding-right:0}.input-group .form-control{float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block !important;height:auto !important;padding-bottom:0;overflow:visible !important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-left:0;padding-right:0}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px;height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:none}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media (min-width:768px){.navbar-left{float:left !important}.navbar-right{float:right !important}}.navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);margin-top:8px;margin-bottom:8px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;padding-left:0;vertical-align:middle}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#e7e7e7;color:#555}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#080808;color:#fff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;line-height:1.428571429;text-decoration:none;color:#428bca;background-color:#fff;border:1px solid #ddd;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca;cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;background-color:#fff;border-color:#ddd;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:20px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;background-color:#fff;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;color:#fff;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#999;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{display:block;max-width:100%;height:auto;margin-left:auto;margin-right:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0%;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group .list-group-item:first-child{border-top:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel>.list-group:first-child .list-group-item:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>tfoot>tr:first-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tfoot>tr:first-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:first-child>td{border-top:0}.panel>.table-bordered>thead>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px;overflow:hidden}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:auto;overflow-y:scroll;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0, -25%);-ms-transform:translate(0, -25%);transform:translate(0, -25%);-webkit-transition:-webkit-transform 0.3s ease-out;-moz-transition:-moz-transform 0.3s ease-out;-o-transition:-o-transform 0.3s ease-out;transition:transform 0.3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);transform:translate(0, 0)}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box;outline:none}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.428571429px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{margin-top:15px;padding:19px 20px 20px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}.modal-sm{width:300px}.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;right:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top .arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,0.25)}.popover.right .arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom .arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,0.25)}.popover.left .arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:.5;filter:alpha(opacity=50);font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-control.left{background-image:-webkit-linear-gradient(left, color-stop(rgba(0,0,0,0.5) 0), color-stop(rgba(0,0,0,0.0001) 100%));background-image:linear-gradient(to right, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left, color-stop(rgba(0,0,0,0.0001) 0), color-stop(rgba(0,0,0,0.5) 100%));background-image:linear-gradient(to right, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:none;color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important;visibility:hidden !important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none !important}@media (max-width:767px){.visible-xs{display:block !important}table.visible-xs{display:table}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none !important}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block !important}table.visible-sm{display:table}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none !important}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block !important}table.visible-md{display:table}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none !important}@media (min-width:1200px){.visible-lg{display:block !important}table.visible-lg{display:table}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media (max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none !important}}@media (min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none !important}}@media (min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none !important}}@media (min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none !important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}@media print{.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none !important}} +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.svg b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,229 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata></metadata> +<defs> +<font id="glyphicons_halflingsregular" horiz-adv-x="1200" > +<font-face units-per-em="1200" ascent="960" descent="-240" /> +<missing-glyph horiz-adv-x="500" /> +<glyph /> +<glyph /> +<glyph unicode="&#xd;" /> +<glyph unicode=" " /> +<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" /> +<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" /> +<glyph unicode="&#xa0;" /> +<glyph unicode="&#x2000;" horiz-adv-x="652" /> +<glyph unicode="&#x2001;" horiz-adv-x="1304" /> +<glyph unicode="&#x2002;" horiz-adv-x="652" /> +<glyph unicode="&#x2003;" horiz-adv-x="1304" /> +<glyph unicode="&#x2004;" horiz-adv-x="434" /> +<glyph unicode="&#x2005;" horiz-adv-x="326" /> +<glyph unicode="&#x2006;" horiz-adv-x="217" /> +<glyph unicode="&#x2007;" horiz-adv-x="217" /> +<glyph unicode="&#x2008;" horiz-adv-x="163" /> +<glyph unicode="&#x2009;" horiz-adv-x="260" /> +<glyph unicode="&#x200a;" horiz-adv-x="72" /> +<glyph unicode="&#x202f;" horiz-adv-x="260" /> +<glyph unicode="&#x205f;" horiz-adv-x="326" /> +<glyph unicode="&#x20ac;" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" /> +<glyph unicode="&#x2212;" d="M200 400h900v300h-900v-300z" /> +<glyph unicode="&#x2601;" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86t85 208q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" /> +<glyph unicode="&#x2709;" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" /> +<glyph unicode="&#x270f;" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" /> +<glyph unicode="&#xe000;" horiz-adv-x="500" d="M0 0z" /> +<glyph unicode="&#xe001;" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" /> +<glyph unicode="&#xe002;" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q17 -55 85.5 -75.5t147.5 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" /> +<glyph unicode="&#xe003;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" /> +<glyph unicode="&#xe005;" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" /> +<glyph unicode="&#xe006;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" /> +<glyph unicode="&#xe007;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" /> +<glyph unicode="&#xe008;" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" /> +<glyph unicode="&#xe009;" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" /> +<glyph unicode="&#xe010;" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" /> +<glyph unicode="&#xe011;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" /> +<glyph unicode="&#xe012;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" /> +<glyph unicode="&#xe013;" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" /> +<glyph unicode="&#xe014;" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" /> +<glyph unicode="&#xe015;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" /> +<glyph unicode="&#xe016;" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 299q-120 -77 -261 -77q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" /> +<glyph unicode="&#xe017;" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" /> +<glyph unicode="&#xe018;" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" /> +<glyph unicode="&#xe019;" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" /> +<glyph unicode="&#xe020;" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" /> +<glyph unicode="&#xe021;" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" /> +<glyph unicode="&#xe022;" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" /> +<glyph unicode="&#xe023;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" /> +<glyph unicode="&#xe024;" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" /> +<glyph unicode="&#xe025;" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" /> +<glyph unicode="&#xe026;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" /> +<glyph unicode="&#xe027;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" /> +<glyph unicode="&#xe028;" d="M0 25v475l200 700h800q199 -700 200 -700v-475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" /> +<glyph unicode="&#xe029;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" /> +<glyph unicode="&#xe030;" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" /> +<glyph unicode="&#xe031;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" /> +<glyph unicode="&#xe032;" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" /> +<glyph unicode="&#xe033;" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" /> +<glyph unicode="&#xe034;" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" /> +<glyph unicode="&#xe035;" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" /> +<glyph unicode="&#xe036;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" /> +<glyph unicode="&#xe037;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" /> +<glyph unicode="&#xe038;" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" /> +<glyph unicode="&#xe039;" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" /> +<glyph unicode="&#xe040;" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" /> +<glyph unicode="&#xe041;" d="M1 700v475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" /> +<glyph unicode="&#xe042;" d="M2 700v475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" /> +<glyph unicode="&#xe043;" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" /> +<glyph unicode="&#xe044;" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" /> +<glyph unicode="&#xe045;" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" /> +<glyph unicode="&#xe046;" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" /> +<glyph unicode="&#xe047;" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" /> +<glyph unicode="&#xe048;" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v70h471q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" /> +<glyph unicode="&#xe049;" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" /> +<glyph unicode="&#xe050;" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " /> +<glyph unicode="&#xe051;" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" /> +<glyph unicode="&#xe052;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" /> +<glyph unicode="&#xe053;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" /> +<glyph unicode="&#xe054;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" /> +<glyph unicode="&#xe055;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" /> +<glyph unicode="&#xe056;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" /> +<glyph unicode="&#xe057;" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" /> +<glyph unicode="&#xe058;" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" /> +<glyph unicode="&#xe059;" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" /> +<glyph unicode="&#xe060;" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " /> +<glyph unicode="&#xe062;" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" /> +<glyph unicode="&#xe063;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" /> +<glyph unicode="&#xe064;" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 138.5t-64 210.5zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" /> +<glyph unicode="&#xe065;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" /> +<glyph unicode="&#xe066;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" /> +<glyph unicode="&#xe067;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l566 567l-136 137l-430 -431l-147 147z" /> +<glyph unicode="&#xe068;" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" /> +<glyph unicode="&#xe069;" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" /> +<glyph unicode="&#xe070;" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" /> +<glyph unicode="&#xe071;" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" /> +<glyph unicode="&#xe072;" d="M200 0l900 550l-900 550v-1100z" /> +<glyph unicode="&#xe073;" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" /> +<glyph unicode="&#xe074;" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" /> +<glyph unicode="&#xe075;" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" /> +<glyph unicode="&#xe076;" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" /> +<glyph unicode="&#xe077;" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" /> +<glyph unicode="&#xe078;" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" /> +<glyph unicode="&#xe079;" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" /> +<glyph unicode="&#xe080;" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" /> +<glyph unicode="&#xe081;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" /> +<glyph unicode="&#xe082;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM300 500h600v200h-600v-200z" /> +<glyph unicode="&#xe083;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141z" /> +<glyph unicode="&#xe084;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" /> +<glyph unicode="&#xe085;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM363 700h144q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5q19 0 30 -10t11 -26 q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-105 0 -172 -56t-67 -183zM500 300h200v100h-200v-100z" /> +<glyph unicode="&#xe086;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" /> +<glyph unicode="&#xe087;" d="M0 500v200h194q15 60 36 104.5t55.5 86t88 69t126.5 40.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200 v-206q149 48 201 206h-201v200h200q-25 74 -76 127.5t-124 76.5v-204h-200v203q-75 -24 -130 -77.5t-79 -125.5h209v-200h-210z" /> +<glyph unicode="&#xe088;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" /> +<glyph unicode="&#xe089;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" /> +<glyph unicode="&#xe090;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" /> +<glyph unicode="&#xe091;" d="M0 547l600 453v-300h600v-300h-600v-301z" /> +<glyph unicode="&#xe092;" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" /> +<glyph unicode="&#xe093;" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" /> +<glyph unicode="&#xe094;" d="M104 600h296v600h300v-600h298l-449 -600z" /> +<glyph unicode="&#xe095;" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" /> +<glyph unicode="&#xe096;" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" /> +<glyph unicode="&#xe097;" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" /> +<glyph unicode="&#xe101;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-33 14.5h-207q-20 0 -32 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" /> +<glyph unicode="&#xe102;" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111v6t-1 15t-3 18l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6h-111v-100z M100 0h400v400h-400v-400zM200 900q-3 0 14 48t35 96l18 47l214 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" /> +<glyph unicode="&#xe103;" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" /> +<glyph unicode="&#xe104;" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" /> +<glyph unicode="&#xe105;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" /> +<glyph unicode="&#xe106;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" /> +<glyph unicode="&#xe107;" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 33 -48 36t-48 -29l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" /> +<glyph unicode="&#xe108;" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -21 -13 -29t-32 1l-94 78h-222l-94 -78q-19 -9 -32 -1t-13 29v64 q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" /> +<glyph unicode="&#xe109;" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" /> +<glyph unicode="&#xe110;" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" /> +<glyph unicode="&#xe111;" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" /> +<glyph unicode="&#xe112;" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" /> +<glyph unicode="&#xe113;" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" /> +<glyph unicode="&#xe114;" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" /> +<glyph unicode="&#xe115;" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" /> +<glyph unicode="&#xe116;" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" /> +<glyph unicode="&#xe117;" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" /> +<glyph unicode="&#xe118;" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" /> +<glyph unicode="&#xe119;" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" /> +<glyph unicode="&#xe120;" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" /> +<glyph unicode="&#xe121;" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" /> +<glyph unicode="&#xe122;" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM99 500v250v5q0 13 0.5 18.5t2.5 13t8 10.5t15 3h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35q-56 337 -56 351z M1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" /> +<glyph unicode="&#xe123;" d="M74 350q0 21 13.5 35.5t33.5 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-22 -9 -63 -23t-167.5 -37 t-251.5 -23t-245.5 20.5t-178.5 41.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" /> +<glyph unicode="&#xe124;" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" /> +<glyph unicode="&#xe125;" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q123 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 212l100 213h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" /> +<glyph unicode="&#xe126;" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q123 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" /> +<glyph unicode="&#xe127;" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" /> +<glyph unicode="&#xe128;" d="M-101 651q0 72 54 110t139 37h302l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 16.5 -10.5t26 -26t16.5 -36.5v-526q0 -13 -85.5 -93.5t-93.5 -80.5h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l106 89v502l-342 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM999 201v600h200v-600h-200z" /> +<glyph unicode="&#xe129;" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6v7.5v7v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" /> +<glyph unicode="&#xe130;" d="M1 585q-15 -31 7 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85l-1 -302q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM76 565l237 339h503l89 -100v-294l-340 -130 q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" /> +<glyph unicode="&#xe131;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 500h300l-2 -194l402 294l-402 298v-197h-298v-201z" /> +<glyph unicode="&#xe132;" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l400 -294v194h302v201h-300v197z" /> +<glyph unicode="&#xe133;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" /> +<glyph unicode="&#xe134;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" /> +<glyph unicode="&#xe135;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -34 5.5 -93t7.5 -87q0 -9 17 -44t16 -60q12 0 23 -5.5 t23 -15t20 -13.5q20 -10 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55.5t-20 -57.5q12 -21 22.5 -34.5t28 -27t36.5 -17.5q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q101 -2 221 111q31 30 47 48t34 49t21 62q-14 9 -37.5 9.5t-35.5 7.5q-14 7 -49 15t-52 19 q-9 0 -39.5 -0.5t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q8 16 22 22q6 -1 26 -1.5t33.5 -4.5t19.5 -13q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5 t5.5 57.5q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 41 1 44q31 -13 58.5 -14.5t39.5 3.5l11 4q6 36 -17 53.5t-64 28.5t-56 23 q-19 -3 -37 0q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -46 0t-45 -3q-20 -6 -51.5 -25.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79zM518 915q3 12 16 30.5t16 25.5q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -18 8 -42.5t16.5 -44 t9.5 -23.5q-6 1 -39 5t-53.5 10t-36.5 16z" /> +<glyph unicode="&#xe136;" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" /> +<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" /> +<glyph unicode="&#xe138;" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" /> +<glyph unicode="&#xe139;" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" /> +<glyph unicode="&#xe140;" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" /> +<glyph unicode="&#xe141;" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM513 609q0 32 21 56.5t52 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-16 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5q-37 0 -62.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" /> +<glyph unicode="&#xe142;" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -79.5 -17t-67.5 -51l-388 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23q38 0 53 -36 q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60l517 511 q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" /> +<glyph unicode="&#xe143;" d="M79 784q0 131 99 229.5t230 98.5q144 0 242 -129q103 129 245 129q130 0 227 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100l-84.5 84.5t-68 74t-60 78t-33.5 70.5t-15 78z M250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-106 48.5q-73 0 -131 -83l-118 -171l-114 174q-51 80 -124 80q-59 0 -108.5 -49.5t-49.5 -118.5z" /> +<glyph unicode="&#xe144;" d="M57 353q0 -94 66 -160l141 -141q66 -66 159 -66q95 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-12 12 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141l19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -18q46 -46 77 -99l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" /> +<glyph unicode="&#xe145;" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" /> +<glyph unicode="&#xe146;" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" /> +<glyph unicode="&#xe148;" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335l-27 7q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5v-307l64 -14 q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5zM700 237 q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" /> +<glyph unicode="&#xe149;" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -11 2.5 -24.5t5.5 -24t9.5 -26.5t10.5 -25t14 -27.5t14 -25.5 t15.5 -27t13.5 -24h242v-100h-197q8 -50 -2.5 -115t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q32 1 102 -16t104 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10 t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5t-30 142.5h-221z" /> +<glyph unicode="&#xe150;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" /> +<glyph unicode="&#xe151;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" /> +<glyph unicode="&#xe152;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" /> +<glyph unicode="&#xe153;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" /> +<glyph unicode="&#xe154;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" /> +<glyph unicode="&#xe155;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" /> +<glyph unicode="&#xe156;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" /> +<glyph unicode="&#xe157;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" /> +<glyph unicode="&#xe158;" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" /> +<glyph unicode="&#xe159;" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" /> +<glyph unicode="&#xe160;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" /> +<glyph unicode="&#xe161;" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" /> +<glyph unicode="&#xe162;" d="M216 519q10 -19 32 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8l9 -1q13 0 26 16l538 630q15 19 6 36q-8 18 -32 16h-300q1 4 78 219.5t79 227.5q2 17 -6 27l-8 8h-9q-16 0 -25 -15q-4 -5 -98.5 -111.5t-228 -257t-209.5 -238.5q-17 -19 -7 -40z" /> +<glyph unicode="&#xe163;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " /> +<glyph unicode="&#xe164;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" /> +<glyph unicode="&#xe165;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" /> +<glyph unicode="&#xe166;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" /> +<glyph unicode="&#xe167;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" /> +<glyph unicode="&#xe168;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" /> +<glyph unicode="&#xe169;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 401h700v699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" /> +<glyph unicode="&#xe170;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l248 -237v700h-699zM900 150h100v50h-100v-50z" /> +<glyph unicode="&#xe171;" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" /> +<glyph unicode="&#xe172;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" /> +<glyph unicode="&#xe173;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" /> +<glyph unicode="&#xe174;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" /> +<glyph unicode="&#xe175;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" /> +<glyph unicode="&#xe176;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" /> +<glyph unicode="&#xe177;" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" /> +<glyph unicode="&#xe178;" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" /> +<glyph unicode="&#xe179;" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -117q-25 -16 -43.5 -50.5t-18.5 -65.5v-359z" /> +<glyph unicode="&#xe180;" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" /> +<glyph unicode="&#xe181;" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" /> +<glyph unicode="&#xe182;" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q16 17 13 40.5t-22 37.5l-192 136q-19 14 -45 12t-42 -19l-119 -118q-143 103 -267 227q-126 126 -227 268l118 118q17 17 20 41.5 t-11 44.5l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" /> +<glyph unicode="&#xe183;" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -15 -35.5t-35 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" /> +<glyph unicode="&#xe184;" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" /> +<glyph unicode="&#xe185;" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" /> +<glyph unicode="&#xe186;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" /> +<glyph unicode="&#xe187;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" /> +<glyph unicode="&#xe188;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" /> +<glyph unicode="&#xe189;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" /> +<glyph unicode="&#xe190;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" /> +<glyph unicode="&#xe191;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" /> +<glyph unicode="&#xe192;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" /> +<glyph unicode="&#xe193;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" /> +<glyph unicode="&#xe194;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" /> +<glyph unicode="&#xe195;" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" /> +<glyph unicode="&#xe197;" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86t85 208q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300 h200l-300 -300z" /> +<glyph unicode="&#xe198;" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104t60.5 178q0 121 -85 207.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" /> +<glyph unicode="&#xe199;" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" /> +<glyph unicode="&#xe200;" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -12t1 -11q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" /> +</font> +</defs></svg> +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/glyphicons-halflings-regular.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.svg b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.svg @@ -0,0 +1,251 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata> +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom +</metadata> +<defs> +<font id="OpenSansBold" horiz-adv-x="1169" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="&#x09;" horiz-adv-x="532" /> +<glyph unicode="&#xa0;" horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="586" d="M117 143q0 84 45 127t131 43q83 0 128.5 -44t45.5 -126q0 -79 -46 -124.5t-128 -45.5q-84 0 -130 44.5t-46 125.5zM121 1462h346l-51 -977h-244z" /> +<glyph unicode="&#x22;" horiz-adv-x="967" d="M133 1462h279l-41 -528h-197zM555 1462h279l-41 -528h-197z" /> +<glyph unicode="#" horiz-adv-x="1323" d="M45 406v206h277l47 232h-252v209h289l77 407h219l-77 -407h198l78 407h215l-78 -407h240v-209h-279l-47 -232h258v-206h-297l-77 -406h-220l78 406h-194l-76 -406h-215l74 406h-238zM539 612h196l47 232h-196z" /> +<glyph unicode="$" d="M88 1049q0 145 113.5 238.5t316.5 113.5v153h137v-149q229 -10 414 -92l-94 -234q-156 64 -320 78v-295q195 -75 277.5 -130t121 -121t38.5 -154q0 -159 -115 -255.5t-322 -115.5v-205h-137v201q-244 5 -428 86v264q87 -43 209.5 -76t218.5 -39v310l-67 26 q-198 78 -280.5 169.5t-82.5 226.5zM389 1049q0 -44 30.5 -72.5t98.5 -58.5v235q-129 -19 -129 -104zM655 324q136 23 136 118q0 42 -34 71t-102 60v-249z" /> +<glyph unicode="%" horiz-adv-x="1845" d="M63 1026q0 457 345 457q169 0 259.5 -118.5t90.5 -338.5q0 -230 -89 -345.5t-261 -115.5q-165 0 -255 118.5t-90 342.5zM315 1024q0 -127 22.5 -189.5t72.5 -62.5q96 0 96 252q0 250 -96 250q-50 0 -72.5 -61.5t-22.5 -188.5zM395 0l811 1462h240l-811 -1462h-240z M1087 442q0 457 345 457q169 0 259.5 -118.5t90.5 -338.5q0 -229 -89 -344.5t-261 -115.5q-165 0 -255 118.5t-90 341.5zM1339 440q0 -127 22.5 -189.5t72.5 -62.5q96 0 96 252q0 250 -96 250q-50 0 -72.5 -61.5t-22.5 -188.5z" /> +<glyph unicode="&#x26;" horiz-adv-x="1536" d="M82 395q0 137 60.5 233.5t207.5 180.5q-75 86 -109 164.5t-34 171.5q0 152 116.5 245t311.5 93q186 0 297.5 -86.5t111.5 -231.5q0 -119 -69 -217.5t-223 -187.5l284 -277q71 117 123 301h318q-36 -135 -99 -263.5t-143 -227.5l301 -293h-377l-115 113 q-191 -133 -432 -133q-244 0 -387 112t-143 303zM403 424q0 -86 64.5 -137t165.5 -51q126 0 227 61l-332 330q-58 -44 -91.5 -92t-33.5 -111zM489 1124q0 -88 95 -194q86 48 132 94.5t46 108.5q0 53 -36 83.5t-93 30.5q-67 0 -105.5 -32t-38.5 -91z" /> +<glyph unicode="'" horiz-adv-x="545" d="M133 1462h279l-41 -528h-197z" /> +<glyph unicode="(" horiz-adv-x="694" d="M82 561q0 265 77.5 496t223.5 405h250q-141 -193 -213 -424t-72 -475q0 -245 73.5 -473.5t209.5 -413.5h-248q-147 170 -224 397t-77 488z" /> +<glyph unicode=")" horiz-adv-x="694" d="M61 1462h250q147 -175 224 -406.5t77 -494.5t-77.5 -490t-223.5 -395h-248q135 184 209 412.5t74 474.5q0 244 -72 475t-213 424z" /> +<glyph unicode="*" horiz-adv-x="1116" d="M63 1042l39 250l365 -104l-41 368h262l-41 -368l373 104l33 -252l-340 -24l223 -297l-227 -121l-156 313l-137 -311l-236 119l221 297z" /> +<glyph unicode="+" d="M88 612v219h387v390h219v-390h387v-219h-387v-385h-219v385h-387z" /> +<glyph unicode="," horiz-adv-x="594" d="M63 -264q65 266 101 502h280l15 -23q-52 -202 -176 -479h-220z" /> +<glyph unicode="-" horiz-adv-x="659" d="M61 424v250h537v-250h-537z" /> +<glyph unicode="." horiz-adv-x="584" d="M117 143q0 84 45 127t131 43q83 0 128.5 -44t45.5 -126q0 -79 -46 -124.5t-128 -45.5q-84 0 -130 44.5t-46 125.5z" /> +<glyph unicode="/" horiz-adv-x="846" d="M14 0l545 1462h277l-545 -1462h-277z" /> +<glyph unicode="0" d="M74 731q0 387 125 570.5t385 183.5q253 0 382.5 -192t129.5 -562q0 -383 -125.5 -567t-386.5 -184q-253 0 -381.5 190t-128.5 561zM381 731q0 -269 46.5 -385.5t156.5 -116.5q108 0 156 118t48 384q0 269 -48.5 386.5t-155.5 117.5q-109 0 -156 -117.5t-47 -386.5z" /> +<glyph unicode="1" d="M121 1087l471 375h254v-1462h-309v846l3 139l5 152q-77 -77 -107 -101l-168 -135z" /> +<glyph unicode="2" d="M78 1274q108 92 179 130t155 58.5t188 20.5q137 0 242 -50t163 -140t58 -206q0 -101 -35.5 -189.5t-110 -181.5t-262.5 -265l-188 -177v-14h637v-260h-1022v215l367 371q163 167 213 231.5t72 119.5t22 114q0 88 -48.5 131t-129.5 43q-85 0 -165 -39t-167 -111z" /> +<glyph unicode="3" d="M78 59v263q85 -43 187 -70t202 -27q153 0 226 52t73 167q0 103 -84 146t-268 43h-111v237h113q170 0 248.5 44.5t78.5 152.5q0 166 -208 166q-72 0 -146.5 -24t-165.5 -83l-143 213q200 144 477 144q227 0 358.5 -92t131.5 -256q0 -137 -83 -233t-233 -132v-6 q177 -22 268 -107.5t91 -230.5q0 -211 -153 -328.5t-437 -117.5q-238 0 -422 79z" /> +<glyph unicode="4" d="M35 303v215l641 944h285v-919h176v-240h-176v-303h-302v303h-624zM307 543h352v248q0 62 5 180t8 137h-8q-37 -82 -89 -160z" /> +<glyph unicode="5" d="M100 59v267q79 -42 184 -68.5t199 -26.5q283 0 283 232q0 221 -293 221q-53 0 -117 -10.5t-104 -22.5l-123 66l55 745h793v-262h-522l-27 -287l35 7q61 14 151 14q212 0 337.5 -119t125.5 -326q0 -245 -151 -377t-432 -132q-244 0 -394 79z" /> +<glyph unicode="6" d="M72 621q0 434 183.5 646t549.5 212q125 0 196 -15v-247q-89 20 -176 20q-159 0 -259.5 -48t-150.5 -142t-59 -267h13q99 170 317 170q196 0 307 -123t111 -340q0 -234 -132 -370.5t-366 -136.5q-162 0 -282.5 75t-186 219t-65.5 347zM379 510q0 -119 62.5 -201t158.5 -82 q99 0 152 66.5t53 189.5q0 107 -49.5 168.5t-149.5 61.5q-94 0 -160.5 -61t-66.5 -142z" /> +<glyph unicode="7" d="M55 1200v260h1049v-194l-553 -1266h-324l549 1200h-721z" /> +<glyph unicode="8" d="M72 371q0 125 66.5 222t213.5 171q-125 79 -180 169t-55 197q0 157 130 254t339 97q210 0 338.5 -95.5t128.5 -257.5q0 -112 -62 -199.5t-200 -156.5q164 -88 235.5 -183.5t71.5 -209.5q0 -180 -141 -289.5t-371 -109.5q-240 0 -377 102t-137 289zM358 389q0 -86 60 -134 t164 -48q115 0 172 49.5t57 130.5q0 67 -56.5 125.5t-183.5 124.5q-213 -98 -213 -248zM408 1106q0 -60 38.5 -107.5t139.5 -97.5q98 46 137 94t39 111q0 69 -50 109t-128 40q-79 0 -127.5 -40.5t-48.5 -108.5z" /> +<glyph unicode="9" d="M66 971q0 235 133.5 371.5t363.5 136.5q162 0 283.5 -76t186.5 -220.5t65 -344.5q0 -432 -182 -645t-551 -213q-130 0 -197 14v248q84 -21 176 -21q155 0 255 45.5t153 143t61 268.5h-12q-58 -94 -134 -132t-190 -38q-191 0 -301 122.5t-110 340.5zM365 975 q0 -106 49 -168t149 -62q94 0 161 61.5t67 141.5q0 119 -62.5 201t-159.5 82q-96 0 -150 -66t-54 -190z" /> +<glyph unicode=":" horiz-adv-x="584" d="M117 143q0 84 45 127t131 43q83 0 128.5 -44t45.5 -126q0 -79 -46 -124.5t-128 -45.5q-84 0 -130 44.5t-46 125.5zM117 969q0 84 45 127t131 43q83 0 128.5 -44t45.5 -126q0 -81 -46.5 -125.5t-127.5 -44.5q-84 0 -130 44t-46 126z" /> +<glyph unicode=";" horiz-adv-x="594" d="M63 -264q65 266 101 502h280l15 -23q-52 -202 -176 -479h-220zM117 969q0 84 45 127t131 43q83 0 128.5 -44t45.5 -126q0 -81 -46.5 -125.5t-127.5 -44.5q-84 0 -130 44t-46 126z" /> +<glyph unicode="&#x3c;" d="M88 641v143l993 496v-240l-684 -317l684 -281v-239z" /> +<glyph unicode="=" d="M88 418v219h993v-219h-993zM88 805v219h993v-219h-993z" /> +<glyph unicode="&#x3e;" d="M88 203v239l684 281l-684 317v240l993 -496v-143z" /> +<glyph unicode="?" horiz-adv-x="977" d="M6 1358q223 125 473 125q206 0 327.5 -99t121.5 -264q0 -110 -50 -190t-190 -180q-96 -71 -121.5 -108t-25.5 -97v-60h-265v74q0 96 41 167t150 151q105 75 138.5 122t33.5 105q0 65 -48 99t-134 34q-150 0 -342 -98zM244 143q0 84 45 127t131 43q83 0 128.5 -44 t45.5 -126q0 -79 -46 -124.5t-128 -45.5q-84 0 -130 44.5t-46 125.5z" /> +<glyph unicode="@" horiz-adv-x="1837" d="M102 602q0 247 108.5 448.5t309 316t461.5 114.5q220 0 393 -90t267 -256t94 -383q0 -144 -46 -263.5t-130 -187.5t-195 -68q-74 0 -131 35.5t-82 93.5h-16q-108 -129 -275 -129q-177 0 -279 106.5t-102 291.5q0 211 134 340t350 129q86 0 189.5 -16.5t170.5 -39.5 l-23 -489q0 -139 76 -139q64 0 102 93.5t38 244.5q0 161 -67 284.5t-188.5 188.5t-277.5 65q-202 0 -351 -83t-228.5 -239.5t-79.5 -361.5q0 -276 147.5 -423.5t427.5 -147.5q106 0 233 23.5t250 68.5v-192q-214 -91 -475 -91q-380 0 -592.5 200t-212.5 556zM711 627 q0 -211 172 -211q90 0 137 63.5t57 206.5l13 221q-51 11 -115 11q-125 0 -194.5 -78t-69.5 -213z" /> +<glyph unicode="A" horiz-adv-x="1413" d="M0 0l516 1468h379l518 -1468h-334l-106 348h-533l-106 -348h-334zM518 608h381q-147 473 -165.5 535t-26.5 98q-33 -128 -189 -633z" /> +<glyph unicode="B" horiz-adv-x="1376" d="M184 0v1462h455q311 0 451.5 -88.5t140.5 -281.5q0 -131 -61.5 -215t-163.5 -101v-10q139 -31 200.5 -116t61.5 -226q0 -200 -144.5 -312t-392.5 -112h-547zM494 256h202q128 0 189 49t61 150q0 182 -260 182h-192v-381zM494 883h180q126 0 182.5 39t56.5 129 q0 84 -61.5 120.5t-194.5 36.5h-163v-325z" /> +<glyph unicode="C" horiz-adv-x="1305" d="M119 729q0 228 83 399.5t238.5 263t364.5 91.5q213 0 428 -103l-100 -252q-82 39 -165 68t-163 29q-175 0 -271 -131.5t-96 -366.5q0 -489 367 -489q154 0 373 77v-260q-180 -75 -402 -75q-319 0 -488 193.5t-169 555.5z" /> +<glyph unicode="D" horiz-adv-x="1516" d="M184 0v1462h459q358 0 556 -189t198 -528q0 -361 -205.5 -553t-593.5 -192h-414zM494 256h133q448 0 448 481q0 471 -416 471h-165v-952z" /> +<glyph unicode="E" horiz-adv-x="1147" d="M184 0v1462h842v-254h-532v-321h495v-254h-495v-377h532v-256h-842z" /> +<glyph unicode="F" horiz-adv-x="1124" d="M184 0v1462h838v-254h-533v-377h496v-253h-496v-578h-305z" /> +<glyph unicode="G" horiz-adv-x="1483" d="M119 733q0 354 202.5 552t561.5 198q225 0 434 -90l-103 -248q-160 80 -333 80q-201 0 -322 -135t-121 -363q0 -238 97.5 -363.5t283.5 -125.5q97 0 197 20v305h-277v258h580v-758q-141 -46 -265.5 -64.5t-254.5 -18.5q-331 0 -505.5 194.5t-174.5 558.5z" /> +<glyph unicode="H" horiz-adv-x="1567" d="M184 0v1462h310v-573h579v573h309v-1462h-309v631h-579v-631h-310z" /> +<glyph unicode="I" horiz-adv-x="678" d="M184 0v1462h310v-1462h-310z" /> +<glyph unicode="J" horiz-adv-x="678" d="M-152 -150q80 -20 146 -20q102 0 146 63.5t44 198.5v1370h310v-1368q0 -256 -117 -390t-346 -134q-105 0 -183 22v258z" /> +<glyph unicode="K" horiz-adv-x="1360" d="M184 0v1462h310v-669l122 172l396 497h344l-510 -647l514 -815h-352l-383 616l-131 -94v-522h-310z" /> +<glyph unicode="L" horiz-adv-x="1157" d="M184 0v1462h310v-1206h593v-256h-903z" /> +<glyph unicode="M" horiz-adv-x="1931" d="M184 0v1462h422l346 -1118h6l367 1118h422v-1462h-289v692q0 49 1.5 113t13.5 340h-9l-377 -1145h-284l-352 1147h-9q19 -350 19 -467v-680h-277z" /> +<glyph unicode="N" horiz-adv-x="1665" d="M184 0v1462h391l635 -1095h7q-15 285 -15 403v692h279v-1462h-394l-636 1106h-9q19 -293 19 -418v-688h-277z" /> +<glyph unicode="O" horiz-adv-x="1630" d="M119 735q0 365 180.5 557.5t517.5 192.5t515.5 -194t178.5 -558q0 -363 -180 -558t-516 -195t-516 195t-180 560zM444 733q0 -245 93 -369t278 -124q371 0 371 493q0 494 -369 494q-185 0 -279 -124.5t-94 -369.5z" /> +<glyph unicode="P" horiz-adv-x="1286" d="M184 0v1462h467q266 0 404.5 -114.5t138.5 -341.5q0 -236 -147.5 -361t-419.5 -125h-133v-520h-310zM494 774h102q143 0 214 56.5t71 164.5q0 109 -59.5 161t-186.5 52h-141v-434z" /> +<glyph unicode="Q" horiz-adv-x="1630" d="M119 735q0 365 180.5 557.5t517.5 192.5t515.5 -194t178.5 -558q0 -258 -91.5 -432.5t-268.5 -255.5l352 -393h-397l-268 328h-23q-336 0 -516 195t-180 560zM444 733q0 -245 93 -369t278 -124q371 0 371 493q0 494 -369 494q-185 0 -279 -124.5t-94 -369.5z" /> +<glyph unicode="R" horiz-adv-x="1352" d="M184 0v1462h426q298 0 441 -108.5t143 -329.5q0 -129 -71 -229.5t-201 -157.5q330 -493 430 -637h-344l-349 561h-165v-561h-310zM494 813h100q147 0 217 49t70 154q0 104 -71.5 148t-221.5 44h-94v-395z" /> +<glyph unicode="S" horiz-adv-x="1128" d="M94 68v288q148 -66 250.5 -93t187.5 -27q102 0 156.5 39t54.5 116q0 43 -24 76.5t-70.5 64.5t-189.5 99q-134 63 -201 121t-107 135t-40 180q0 194 131.5 305t363.5 111q114 0 217.5 -27t216.5 -76l-100 -241q-117 48 -193.5 67t-150.5 19q-88 0 -135 -41t-47 -107 q0 -41 19 -71.5t60.5 -59t196.5 -102.5q205 -98 281 -196.5t76 -241.5q0 -198 -142.5 -312t-396.5 -114q-234 0 -414 88z" /> +<glyph unicode="T" horiz-adv-x="1186" d="M41 1204v258h1104v-258h-397v-1204h-310v1204h-397z" /> +<glyph unicode="U" horiz-adv-x="1548" d="M174 520v942h309v-895q0 -169 68 -248t225 -79q152 0 220.5 79.5t68.5 249.5v893h309v-946q0 -162 -72.5 -284t-209.5 -187t-324 -65q-282 0 -438 144.5t-156 395.5z" /> +<glyph unicode="V" horiz-adv-x="1331" d="M0 1462h313l275 -870q23 -77 47.5 -179.5t30.5 -142.5q11 92 75 322l277 870h313l-497 -1462h-338z" /> +<glyph unicode="W" horiz-adv-x="1980" d="M0 1462h305l187 -798q49 -221 71 -383q6 57 27.5 176.5t40.5 185.5l213 819h293l213 -819q14 -55 35 -168t32 -194q10 78 32 194.5t40 188.5l186 798h305l-372 -1462h-353l-198 768q-11 41 -37.5 169.5t-30.5 172.5q-6 -54 -30 -173.5t-37 -170.5l-197 -766h-352z" /> +<glyph unicode="X" horiz-adv-x="1366" d="M0 0l485 754l-454 708h342l315 -526l309 526h334l-459 -725l494 -737h-354l-340 553l-340 -553h-332z" /> +<glyph unicode="Y" horiz-adv-x="1278" d="M0 1462h336l303 -602l305 602h334l-485 -893v-569h-308v559z" /> +<glyph unicode="Z" horiz-adv-x="1186" d="M49 0v201l701 1005h-682v256h1050v-200l-700 -1006h719v-256h-1088z" /> +<glyph unicode="[" horiz-adv-x="678" d="M143 -324v1786h484v-211h-224v-1364h224v-211h-484z" /> +<glyph unicode="\" horiz-adv-x="846" d="M12 1462h277l545 -1462h-277z" /> +<glyph unicode="]" horiz-adv-x="678" d="M51 -113h223v1364h-223v211h484v-1786h-484v211z" /> +<glyph unicode="^" horiz-adv-x="1090" d="M8 520l438 950h144l495 -950h-239l-322 643l-280 -643h-236z" /> +<glyph unicode="_" horiz-adv-x="842" d="M-4 -184h850v-140h-850v140z" /> +<glyph unicode="`" horiz-adv-x="1243" d="M332 1548v21h342q63 -101 235 -301v-27h-202q-63 44 -185 142.5t-190 164.5z" /> +<glyph unicode="a" horiz-adv-x="1237" d="M86 334q0 178 124.5 262.5t375.5 93.5l194 6v49q0 170 -174 170q-134 0 -315 -81l-101 206q193 101 428 101q225 0 345 -98t120 -298v-745h-213l-59 152h-8q-77 -97 -158.5 -134.5t-212.5 -37.5q-161 0 -253.5 92t-92.5 262zM399 332q0 -129 148 -129q106 0 169.5 61 t63.5 162v92l-118 -4q-133 -4 -198 -48t-65 -134z" /> +<glyph unicode="b" horiz-adv-x="1296" d="M160 0v1556h305v-362q0 -69 -12 -221h12q107 166 317 166q198 0 310 -154.5t112 -423.5q0 -277 -115.5 -429t-314.5 -152q-197 0 -309 143h-21l-51 -123h-233zM465 563q0 -180 53.5 -258t169.5 -78q94 0 149.5 86.5t55.5 251.5t-56 247.5t-153 82.5q-113 0 -165 -69.5 t-54 -229.5v-33z" /> +<glyph unicode="c" horiz-adv-x="1053" d="M92 553q0 285 142 435.5t407 150.5q194 0 348 -76l-90 -236q-72 29 -134 47.5t-124 18.5q-238 0 -238 -338q0 -328 238 -328q88 0 163 23.5t150 73.5v-261q-74 -47 -149.5 -65t-190.5 -18q-522 0 -522 573z" /> +<glyph unicode="d" horiz-adv-x="1296" d="M92 557q0 275 114.5 428.5t315.5 153.5q211 0 322 -164h10q-23 125 -23 223v358h306v-1556h-234l-59 145h-13q-104 -165 -317 -165q-197 0 -309.5 153t-112.5 424zM401 553q0 -165 57 -247.5t163 -82.5q117 0 171.5 68t59.5 231v33q0 180 -55.5 258t-180.5 78 q-102 0 -158.5 -86.5t-56.5 -251.5z" /> +<glyph unicode="e" horiz-adv-x="1210" d="M92 551q0 281 140.5 434.5t388.5 153.5q237 0 369 -135t132 -373v-148h-721q5 -130 77 -203t202 -73q101 0 191 21t188 67v-236q-80 -40 -171 -59.5t-222 -19.5q-270 0 -422 149t-152 422zM408 686h428q-2 113 -59 174.5t-154 61.5t-152 -61.5t-63 -174.5z" /> +<glyph unicode="f" horiz-adv-x="793" d="M41 889v147l168 82v82q0 191 94 279t301 88q158 0 281 -47l-78 -224q-92 29 -170 29q-65 0 -94 -38.5t-29 -98.5v-70h264v-229h-264v-889h-305v889h-168z" /> +<glyph unicode="g" horiz-adv-x="1157" d="M6 -182q0 101 63 169t185 97q-47 20 -82 65.5t-35 96.5q0 64 37 106.5t107 83.5q-88 38 -139.5 122t-51.5 198q0 183 119 283t340 100q47 0 111.5 -8.5t82.5 -12.5h390v-155l-175 -45q48 -75 48 -168q0 -180 -125.5 -280.5t-348.5 -100.5l-55 3l-45 5q-47 -36 -47 -80 q0 -66 168 -66h190q184 0 280.5 -79t96.5 -232q0 -196 -163.5 -304t-469.5 -108q-234 0 -357.5 81.5t-123.5 228.5zM270 -158q0 -63 60.5 -99t169.5 -36q164 0 257 45t93 123q0 63 -55 87t-170 24h-158q-84 0 -140.5 -39.5t-56.5 -104.5zM381 752q0 -91 41.5 -144t126.5 -53 q86 0 126 53t40 144q0 202 -166 202q-168 0 -168 -202z" /> +<glyph unicode="h" horiz-adv-x="1346" d="M160 0v1556h305v-317q0 -37 -7 -174l-7 -90h16q102 164 324 164q197 0 299 -106t102 -304v-729h-305v653q0 242 -180 242q-128 0 -185 -87t-57 -282v-526h-305z" /> +<glyph unicode="i" horiz-adv-x="625" d="M147 1407q0 149 166 149t166 -149q0 -71 -41.5 -110.5t-124.5 -39.5q-166 0 -166 150zM160 0v1118h305v-1118h-305z" /> +<glyph unicode="j" horiz-adv-x="625" d="M-131 -227q70 -19 143 -19q77 0 112.5 43t35.5 127v1194h305v-1239q0 -178 -103 -274.5t-292 -96.5q-117 0 -201 25v240zM147 1407q0 149 166 149t166 -149q0 -71 -41.5 -110.5t-124.5 -39.5q-166 0 -166 150z" /> +<glyph unicode="k" horiz-adv-x="1270" d="M160 0v1556h305v-694l-16 -254h4l133 170l313 340h344l-444 -485l471 -633h-352l-322 453l-131 -105v-348h-305z" /> +<glyph unicode="l" horiz-adv-x="625" d="M160 0v1556h305v-1556h-305z" /> +<glyph unicode="m" horiz-adv-x="2011" d="M160 0v1118h233l41 -143h17q45 77 130 120.5t195 43.5q251 0 340 -164h27q45 78 132.5 121t197.5 43q190 0 287.5 -97.5t97.5 -312.5v-729h-306v653q0 121 -40.5 181.5t-127.5 60.5q-112 0 -167.5 -80t-55.5 -254v-561h-305v653q0 121 -40.5 181.5t-127.5 60.5 q-117 0 -170 -86t-53 -283v-526h-305z" /> +<glyph unicode="n" horiz-adv-x="1346" d="M160 0v1118h233l41 -143h17q51 81 140.5 122.5t203.5 41.5q195 0 296 -105.5t101 -304.5v-729h-305v653q0 121 -43 181.5t-137 60.5q-128 0 -185 -85.5t-57 -283.5v-526h-305z" /> +<glyph unicode="o" horiz-adv-x="1268" d="M92 561q0 274 143 426t402 152q161 0 284 -70t189 -201t66 -307q0 -273 -144 -427t-401 -154q-161 0 -284 70.5t-189 202.5t-66 308zM403 561q0 -166 54.5 -251t177.5 -85q122 0 175.5 84.5t53.5 251.5q0 166 -54 249t-177 83q-122 0 -176 -82.5t-54 -249.5z" /> +<glyph unicode="p" horiz-adv-x="1296" d="M160 -492v1610h248l43 -145h14q107 166 317 166q198 0 310 -153t112 -425q0 -179 -52.5 -311t-149.5 -201t-228 -69q-197 0 -309 143h-16q16 -140 16 -162v-453h-305zM465 563q0 -180 53.5 -258t169.5 -78q205 0 205 338q0 165 -50.5 247.5t-158.5 82.5 q-113 0 -165 -69.5t-54 -229.5v-33z" /> +<glyph unicode="q" horiz-adv-x="1296" d="M92 557q0 274 114.5 428t313.5 154q106 0 185 -40t139 -124h8l27 143h258v-1610h-306v469q0 61 13 168h-13q-49 -81 -130 -123t-187 -42q-198 0 -310 152.5t-112 424.5zM403 553q0 -168 53.5 -251t166.5 -83q116 0 170 66.5t59 232.5v37q0 180 -55.5 258t-178.5 78 q-215 0 -215 -338z" /> +<glyph unicode="r" horiz-adv-x="930" d="M160 0v1118h231l45 -188h15q52 94 140.5 151.5t192.5 57.5q62 0 103 -9l-23 -286q-37 10 -90 10q-146 0 -227.5 -75t-81.5 -210v-569h-305z" /> +<glyph unicode="s" horiz-adv-x="1018" d="M92 827q0 149 115.5 230.5t327.5 81.5q202 0 393 -88l-92 -220q-84 36 -157 59t-149 23q-135 0 -135 -73q0 -41 43.5 -71t190.5 -89q131 -53 192 -99t90 -106t29 -143q0 -172 -119.5 -262t-357.5 -90q-122 0 -208 16.5t-161 48.5v252q85 -40 191.5 -67t187.5 -27 q166 0 166 96q0 36 -22 58.5t-76 51t-144 66.5q-129 54 -189.5 100t-88 105.5t-27.5 146.5z" /> +<glyph unicode="t" horiz-adv-x="889" d="M47 889v129l168 102l88 236h195v-238h313v-229h-313v-539q0 -65 36.5 -96t96.5 -31q80 0 192 35v-227q-114 -51 -280 -51q-183 0 -266.5 92.5t-83.5 277.5v539h-146z" /> +<glyph unicode="u" horiz-adv-x="1346" d="M154 389v729h305v-653q0 -121 43 -181.5t137 -60.5q128 0 185 85.5t57 283.5v526h305v-1118h-234l-41 143h-16q-49 -78 -139 -120.5t-205 -42.5q-197 0 -297 105.5t-100 303.5z" /> +<glyph unicode="v" horiz-adv-x="1165" d="M0 1118h319l216 -637q36 -121 45 -229h6q5 96 45 229l215 637h319l-426 -1118h-313z" /> +<glyph unicode="w" horiz-adv-x="1753" d="M20 1118h304l129 -495q31 -133 63 -367h6q4 76 35 241l16 85l138 536h336l131 -536q4 -22 12.5 -65t16.5 -91.5t14.5 -95t7.5 -74.5h6q9 72 32 197.5t33 169.5l134 495h299l-322 -1118h-332l-86 391l-116 494h-7l-204 -885h-328z" /> +<glyph unicode="x" horiz-adv-x="1184" d="M10 0l379 571l-360 547h346l217 -356l219 356h346l-364 -547l381 -571h-347l-235 383l-236 -383h-346z" /> +<glyph unicode="y" horiz-adv-x="1165" d="M0 1118h334l211 -629q27 -82 37 -194h6q11 103 43 194l207 629h327l-473 -1261q-65 -175 -185.5 -262t-281.5 -87q-79 0 -155 17v242q55 -13 120 -13q81 0 141.5 49.5t94.5 149.5l18 55z" /> +<glyph unicode="z" horiz-adv-x="999" d="M55 0v180l518 705h-487v233h834v-198l-504 -687h522v-233h-883z" /> +<glyph unicode="{" horiz-adv-x="807" d="M31 449v239q126 0 191 44t65 126v8v318q0 153 97 215.5t341 62.5v-225q-99 -3 -136.5 -38t-37.5 -103v-299q-6 -188 -234 -222v-12q234 -35 234 -212v-9v-299q0 -68 37 -103t137 -38v-226q-244 0 -341 62.5t-97 216.5v315q0 87 -65.5 133t-190.5 46z" /> +<glyph unicode="|" horiz-adv-x="1128" d="M455 -465v2015h219v-2015h-219z" /> +<glyph unicode="}" horiz-adv-x="807" d="M82 -98q99 2 136.5 36t37.5 105v299v11q0 86 59 139.5t174 70.5v12q-227 34 -233 222v299q0 70 -37 104t-137 37v225q167 0 262 -26.5t135.5 -84t40.5 -167.5v-318v-10q0 -84 61.5 -126t194.5 -42v-239q-125 0 -190.5 -41t-65.5 -138v-315q0 -112 -41 -169t-135.5 -83.5 t-261.5 -26.5v226z" /> +<glyph unicode="~" d="M88 551v231q103 109 256 109q73 0 137.5 -16t139.5 -48q129 -55 227 -55q53 0 116 32t117 89v-231q-101 -109 -256 -109q-66 0 -126 13t-150 50q-131 56 -227 56q-55 0 -117.5 -33.5t-116.5 -87.5z" /> +<glyph unicode="&#xa1;" horiz-adv-x="586" d="M117 -369l51 975h244l51 -975h-346zM117 948q0 81 46.5 125.5t127.5 44.5q84 0 130 -44t46 -126q0 -84 -45 -127t-131 -43q-83 0 -128.5 44t-45.5 126z" /> +<glyph unicode="&#xa2;" d="M143 741q0 261 104.5 403t315.5 173v166h178v-158q166 -9 299 -74l-90 -235q-72 29 -134 47t-124 18q-121 0 -179 -83.5t-58 -254.5q0 -327 237 -327q82 0 148 15.5t166 60.5v-254q-127 -61 -265 -70v-188h-178v196q-420 59 -420 565z" /> +<glyph unicode="&#xa3;" d="M82 0v248q103 44 141.5 101t38.5 157v145h-178v219h178v195q0 201 114.5 309.5t323.5 108.5q195 0 390 -82l-93 -230q-157 64 -272 64q-78 0 -120 -44.5t-42 -127.5v-193h375v-219h-375v-143q0 -170 -151 -248h718v-260h-1048z" /> +<glyph unicode="&#xa4;" d="M113 1047l147 147l127 -127q91 53 197 53q105 0 196 -55l127 129l150 -143l-129 -129q53 -89 53 -199q0 -107 -53 -199l125 -125l-146 -145l-127 125q-95 -51 -196 -51q-115 0 -199 51l-125 -123l-145 145l127 125q-54 93 -54 197q0 102 54 197zM395 723 q0 -77 54.5 -132.5t134.5 -55.5q81 0 136.5 55t55.5 133q0 80 -56.5 135t-135.5 55q-78 0 -133.5 -56t-55.5 -134z" /> +<glyph unicode="&#xa5;" d="M6 1462h316l262 -602l264 602h313l-383 -747h195v-178h-246v-138h246v-178h-246v-221h-287v221h-247v178h247v138h-247v178h190z" /> +<glyph unicode="&#xa6;" horiz-adv-x="1128" d="M455 350h219v-815h-219v815zM455 735v815h219v-815h-219z" /> +<glyph unicode="&#xa7;" horiz-adv-x="995" d="M106 59v207q81 -41 180 -69.5t169 -28.5q194 0 194 117q0 39 -18.5 63t-63.5 49.5t-125 59.5q-183 74 -252 152.5t-69 195.5q0 79 36 144.5t97 105.5q-133 84 -133 233q0 131 111.5 210t293.5 79q170 0 363 -84l-82 -190q-68 32 -138.5 57.5t-148.5 25.5q-81 0 -118 -23 t-37 -71q0 -49 49.5 -86t163.5 -82q163 -64 240 -148.5t77 -193.5q0 -177 -125 -260q62 -40 93.5 -92.5t31.5 -126.5q0 -148 -119.5 -235.5t-320.5 -87.5q-203 0 -349 79zM344 827q0 -67 65 -119t181 -98q78 57 78 146q0 68 -50.5 115t-183.5 96q-37 -14 -63.5 -53.5 t-26.5 -86.5z" /> +<glyph unicode="&#xa8;" horiz-adv-x="1243" d="M279 1405q0 65 37.5 100t101.5 35q66 0 103.5 -37t37.5 -98q0 -60 -38 -96.5t-103 -36.5q-64 0 -101.5 35t-37.5 98zM682 1405q0 70 40.5 102.5t100.5 32.5q65 0 103.5 -36t38.5 -99q0 -61 -39 -97t-103 -36q-60 0 -100.5 32.5t-40.5 100.5z" /> +<glyph unicode="&#xa9;" horiz-adv-x="1704" d="M100 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM242 731q0 -164 82 -305.5t224 -223t304 -81.5q164 0 305.5 82t223 224t81.5 304q0 164 -82 305.5t-224 223 t-304 81.5q-164 0 -305.5 -82t-223 -224t-81.5 -304zM461 733q0 220 110.5 342.5t309.5 122.5q149 0 305 -78l-74 -168q-113 58 -217 58q-97 0 -150 -74t-53 -205q0 -280 203 -280q57 0 123 15t123 44v-191q-120 -57 -252 -57q-204 0 -316 125t-112 346z" /> +<glyph unicode="&#xaa;" horiz-adv-x="784" d="M47 975q0 109 82.5 163.5t267.5 63.5l99 4q0 117 -127 117q-81 0 -217 -61l-66 135q66 32 145.5 57t178.5 25q137 0 211.5 -71t74.5 -202v-442h-135l-31 110q-43 -58 -105 -90t-136 -32q-117 0 -179.5 58.5t-62.5 164.5zM252 977q0 -38 23 -56t55 -18q77 0 121.5 41.5 t44.5 106.5v36l-99 -6q-145 -10 -145 -104z" /> +<glyph unicode="&#xab;" horiz-adv-x="1260" d="M82 547v26l371 455l219 -119l-279 -348l279 -348l-219 -119zM588 547v26l370 455l220 -119l-279 -348l279 -348l-220 -119z" /> +<glyph unicode="&#xac;" d="M88 612v219h993v-583h-219v364h-774z" /> +<glyph unicode="&#xad;" horiz-adv-x="659" d="M61 424v250h537v-250h-537z" /> +<glyph unicode="&#xae;" horiz-adv-x="1704" d="M100 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM242 731q0 -164 82 -305.5t224 -223t304 -81.5q164 0 305.5 82t223 224t81.5 304q0 164 -82 305.5t-224 223 t-304 81.5q-164 0 -305.5 -82t-223 -224t-81.5 -304zM543 272v916h264q181 0 265.5 -70t84.5 -213q0 -170 -143 -233l237 -400h-254l-178 338h-47v-338h-229zM772 778h31q66 0 94.5 28.5t28.5 94.5q0 65 -28 92t-97 27h-29v-242z" /> +<glyph unicode="&#xaf;" horiz-adv-x="1024" d="M-6 1556v201h1036v-201h-1036z" /> +<glyph unicode="&#xb0;" horiz-adv-x="877" d="M92 1137q0 92 46 172t126 127t174 47q92 0 172.5 -46t127 -127t46.5 -173q0 -93 -46.5 -173.5t-126.5 -125.5t-173 -45q-145 0 -245.5 99.5t-100.5 244.5zM283 1137q0 -64 44.5 -109t110.5 -45t111 46t45 108q0 63 -45.5 110t-110.5 47q-64 0 -109.5 -46t-45.5 -111z" /> +<glyph unicode="&#xb1;" d="M88 0v219h993v-219h-993zM88 674v219h387v389h219v-389h387v-219h-387v-385h-219v385h-387z" /> +<glyph unicode="&#xb2;" horiz-adv-x="776" d="M47 1354q147 129 336 129q137 0 216 -66.5t79 -183.5q0 -85 -47 -160t-176 -192l-105 -95h352v-200h-647v168l224 219q102 100 130.5 144.5t28.5 94.5q0 38 -24 58t-64 20q-81 0 -180 -88z" /> +<glyph unicode="&#xb3;" horiz-adv-x="776" d="M59 639v190q148 -90 271 -90q143 0 143 107q0 53 -44 79.5t-122 26.5h-112v160h92q83 0 123.5 26t40.5 83q0 38 -25 63t-76 25q-47 0 -89 -19t-99 -59l-101 141q62 47 137.5 78t178.5 31q127 0 208 -64t81 -168q0 -143 -170 -198v-13q94 -20 146 -75t52 -134 q0 -121 -88 -190.5t-274 -69.5q-143 0 -273 70z" /> +<glyph unicode="&#xb4;" horiz-adv-x="1243" d="M332 1241v27q172 200 235 301h342v-21q-52 -52 -177.5 -154.5t-196.5 -152.5h-203z" /> +<glyph unicode="&#xb5;" horiz-adv-x="1352" d="M160 -492v1610h305v-653q0 -121 44 -181.5t138 -60.5q126 0 183 86.5t57 282.5v526h305v-1118h-231l-43 150h-15q-42 -85 -102 -127.5t-148 -42.5q-62 0 -114 23t-84 67l5 -85l5 -157v-320h-305z" /> +<glyph unicode="&#xb6;" horiz-adv-x="1341" d="M113 1042q0 260 109 387t341 127h604v-1816h-161v1616h-166v-1616h-162v819q-62 -18 -146 -18q-216 0 -317.5 125t-101.5 376z" /> +<glyph unicode="&#xb7;" horiz-adv-x="584" d="M117 723q0 84 45 127t131 43q83 0 128.5 -44t45.5 -126q0 -81 -46.5 -125.5t-127.5 -44.5q-84 0 -130 44t-46 126z" /> +<glyph unicode="&#xb8;" horiz-adv-x="420" d="M-37 -303q27 -7 72.5 -14t70.5 -7q72 0 72 62q0 83 -166 108l78 154h193l-27 -61q74 -24 118 -74.5t44 -114.5q0 -128 -75.5 -185t-233.5 -57q-78 0 -146 21v168z" /> +<glyph unicode="&#xb9;" horiz-adv-x="776" d="M92 1227l301 235h191v-876h-238v446l3 112l5 95q-27 -36 -75 -78l-78 -61z" /> +<glyph unicode="&#xba;" horiz-adv-x="795" d="M57 1116q0 169 89.5 266t252.5 97q152 0 245 -98.5t93 -264.5q0 -171 -91.5 -267.5t-250.5 -96.5q-153 0 -245.5 98.5t-92.5 265.5zM260 1116q0 -100 32.5 -150.5t104.5 -50.5t103.5 50.5t31.5 150.5t-31.5 149.5t-103.5 49.5t-104.5 -49.5t-32.5 -149.5z" /> +<glyph unicode="&#xbb;" horiz-adv-x="1260" d="M82 213l278 348l-278 348l219 119l371 -455v-26l-371 -453zM588 213l278 348l-278 348l219 119l371 -455v-26l-371 -453z" /> +<glyph unicode="&#xbc;" horiz-adv-x="1804" d="M46 1227l301 235h191v-876h-238v446l3 112l5 95q-27 -36 -75 -78l-78 -61zM320 0l811 1462h239l-811 -1462h-239zM936 152v154l385 577h236v-563h125v-168h-125v-151h-238v151h-383zM1121 320h198v164q0 86 6 184q-9 -26 -35.5 -80t-41.5 -77z" /> +<glyph unicode="&#xbd;" horiz-adv-x="1804" d="M46 1227l301 235h191v-876h-238v446l3 112l5 95q-27 -36 -75 -78l-78 -61zM320 0l811 1462h239l-811 -1462h-239zM1061 769q147 129 336 129q137 0 216 -66.5t79 -183.5q0 -85 -47 -160t-176 -192l-105 -95h352v-200h-647v168l224 219q102 100 130.5 144.5t28.5 94.5 q0 38 -24 58t-64 20q-81 0 -180 -88z" /> +<glyph unicode="&#xbe;" horiz-adv-x="1804" d="M90 639v190q148 -90 271 -90q143 0 143 107q0 53 -44 79.5t-122 26.5h-112v160h92q83 0 123.5 26t40.5 83q0 38 -25 63t-76 25q-47 0 -89 -19t-99 -59l-101 141q62 47 137.5 78t178.5 31q127 0 208 -64t81 -168q0 -143 -170 -198v-13q94 -20 146 -75t52 -134 q0 -121 -88 -190.5t-274 -69.5q-143 0 -273 70zM391 0l811 1462h239l-811 -1462h-239zM966 152v154l385 577h236v-563h125v-168h-125v-151h-238v151h-383zM1151 320h198v164q0 86 6 184q-9 -26 -35.5 -80t-41.5 -77z" /> +<glyph unicode="&#xbf;" horiz-adv-x="977" d="M61 -29q0 108 48.5 187t191.5 184q95 70 121.5 107t26.5 98v59h264v-74q0 -98 -44.5 -169t-152.5 -148q-109 -78 -137.5 -122t-28.5 -107q0 -57 43.5 -94t132.5 -37q79 0 169 29t186 71l102 -221q-98 -56 -221.5 -90.5t-229.5 -34.5q-220 0 -345.5 96.5t-125.5 265.5z M395 948q0 81 46.5 125.5t127.5 44.5q84 0 130 -44t46 -126q0 -84 -45 -127t-131 -43q-83 0 -128.5 44t-45.5 126z" /> +<glyph unicode="&#xc0;" horiz-adv-x="1413" d="M0 0l516 1468h379l518 -1468h-334l-106 348h-533l-106 -348h-334zM518 608h381q-147 473 -165.5 535t-26.5 98q-33 -128 -189 -633zM338 1886v21h342q63 -101 235 -301v-27h-202q-63 44 -185 142.5t-190 164.5z" /> +<glyph unicode="&#xc1;" horiz-adv-x="1413" d="M0 0l516 1468h379l518 -1468h-334l-106 348h-533l-106 -348h-334zM518 608h381q-147 473 -165.5 535t-26.5 98q-33 -128 -189 -633zM541 1579v27q172 200 235 301h342v-21q-52 -52 -177.5 -154.5t-196.5 -152.5h-203z" /> +<glyph unicode="&#xc2;" horiz-adv-x="1413" d="M0 0l516 1468h379l518 -1468h-334l-106 348h-533l-106 -348h-334zM518 608h381q-147 473 -165.5 535t-26.5 98q-33 -128 -189 -633zM272 1579v27q189 189 256 301h357q31 -52 107.5 -141.5t148.5 -159.5v-27h-203q-157 93 -234 176q-78 -81 -229 -176h-203z" /> +<glyph unicode="&#xc3;" horiz-adv-x="1413" d="M0 0l516 1468h379l518 -1468h-334l-106 348h-533l-106 -348h-334zM518 608h381q-147 473 -165.5 535t-26.5 98q-33 -128 -189 -633zM293 1577q11 145 82.5 227t189.5 82q41 0 80.5 -16.5t78 -36t75.5 -35.5t73 -16q31 0 59.5 26t41.5 80h149q-11 -145 -83.5 -227 t-188.5 -82q-41 0 -80.5 16.5t-78 36t-75.5 36t-73 16.5q-31 0 -59.5 -26.5t-41.5 -80.5h-149z" /> +<glyph unicode="&#xc4;" horiz-adv-x="1413" d="M0 0l516 1468h379l518 -1468h-334l-106 348h-533l-106 -348h-334zM518 608h381q-147 473 -165.5 535t-26.5 98q-33 -128 -189 -633zM365 1743q0 65 37.5 100t101.5 35q66 0 103.5 -37t37.5 -98q0 -60 -38 -96.5t-103 -36.5q-64 0 -101.5 35t-37.5 98zM768 1743 q0 70 40.5 102.5t100.5 32.5q65 0 103.5 -36t38.5 -99q0 -61 -39 -97t-103 -36q-60 0 -100.5 32.5t-40.5 100.5z" /> +<glyph unicode="&#xc5;" horiz-adv-x="1413" d="M0 0l516 1468h379l518 -1468h-334l-106 348h-533l-106 -348h-334zM518 608h381q-147 473 -165.5 535t-26.5 98q-33 -128 -189 -633zM457 1565q0 108 67.5 172.5t180.5 64.5q110 0 182 -66t72 -169q0 -108 -71 -174t-183 -66t-180 64t-68 174zM609 1565q0 -45 24 -71 t72 -26q42 0 69 26t27 71t-27 70.5t-69 25.5t-69 -25.5t-27 -70.5z" /> +<glyph unicode="&#xc6;" horiz-adv-x="1950" d="M0 0l655 1462h1174v-254h-563v-321h526v-254h-526v-377h563v-256h-873v348h-491l-150 -348h-315zM578 608h378v590h-127z" /> +<glyph unicode="&#xc7;" horiz-adv-x="1305" d="M119 729q0 228 83 399.5t238.5 263t364.5 91.5q213 0 428 -103l-100 -252q-82 39 -165 68t-163 29q-175 0 -271 -131.5t-96 -366.5q0 -489 367 -489q154 0 373 77v-260q-180 -75 -402 -75q-319 0 -488 193.5t-169 555.5zM504 -303q27 -7 72.5 -14t70.5 -7q72 0 72 62 q0 83 -166 108l78 154h193l-27 -61q74 -24 118 -74.5t44 -114.5q0 -128 -75.5 -185t-233.5 -57q-78 0 -146 21v168z" /> +<glyph unicode="&#xc8;" horiz-adv-x="1147" d="M184 0v1462h842v-254h-532v-321h495v-254h-495v-377h532v-256h-842zM259 1886v21h342q63 -101 235 -301v-27h-202q-63 44 -185 142.5t-190 164.5z" /> +<glyph unicode="&#xc9;" horiz-adv-x="1147" d="M184 0v1462h842v-254h-532v-321h495v-254h-495v-377h532v-256h-842zM424 1579v27q172 200 235 301h342v-21q-52 -52 -177.5 -154.5t-196.5 -152.5h-203z" /> +<glyph unicode="&#xca;" horiz-adv-x="1147" d="M184 0v1462h842v-254h-532v-321h495v-254h-495v-377h532v-256h-842zM175 1579v27q189 189 256 301h357q31 -52 107.5 -141.5t148.5 -159.5v-27h-203q-157 93 -234 176q-78 -81 -229 -176h-203z" /> +<glyph unicode="&#xcb;" horiz-adv-x="1147" d="M184 0v1462h842v-254h-532v-321h495v-254h-495v-377h532v-256h-842zM272 1743q0 65 37.5 100t101.5 35q66 0 103.5 -37t37.5 -98q0 -60 -38 -96.5t-103 -36.5q-64 0 -101.5 35t-37.5 98zM675 1743q0 70 40.5 102.5t100.5 32.5q65 0 103.5 -36t38.5 -99q0 -61 -39 -97 t-103 -36q-60 0 -100.5 32.5t-40.5 100.5z" /> +<glyph unicode="&#xcc;" horiz-adv-x="678" d="M184 0v1462h310v-1462h-310zM-58 1886v21h342q63 -101 235 -301v-27h-202q-63 44 -185 142.5t-190 164.5z" /> +<glyph unicode="&#xcd;" horiz-adv-x="678" d="M184 0v1462h310v-1462h-310zM167 1579v27q172 200 235 301h342v-21q-52 -52 -177.5 -154.5t-196.5 -152.5h-203z" /> +<glyph unicode="&#xce;" horiz-adv-x="678" d="M184 0v1462h310v-1462h-310zM-96 1579v27q189 189 256 301h357q31 -52 107.5 -141.5t148.5 -159.5v-27h-203q-157 93 -234 176q-78 -81 -229 -176h-203z" /> +<glyph unicode="&#xcf;" horiz-adv-x="678" d="M184 0v1462h310v-1462h-310zM-3 1743q0 65 37.5 100t101.5 35q66 0 103.5 -37t37.5 -98q0 -60 -38 -96.5t-103 -36.5q-64 0 -101.5 35t-37.5 98zM400 1743q0 70 40.5 102.5t100.5 32.5q65 0 103.5 -36t38.5 -99q0 -61 -39 -97t-103 -36q-60 0 -100.5 32.5t-40.5 100.5z " /> +<glyph unicode="&#xd0;" horiz-adv-x="1516" d="M47 596v254h137v612h459q358 0 556 -189t198 -528q0 -361 -205.5 -553t-593.5 -192h-414v596h-137zM494 256h131q450 0 450 481q0 232 -104 351.5t-314 119.5h-163v-358h237v-254h-237v-340z" /> +<glyph unicode="&#xd1;" horiz-adv-x="1665" d="M184 0v1462h391l635 -1095h7q-15 285 -15 403v692h279v-1462h-394l-636 1106h-9q19 -293 19 -418v-688h-277zM418 1577q11 145 82.5 227t189.5 82q41 0 80.5 -16.5t78 -36t75.5 -35.5t73 -16q31 0 59.5 26t41.5 80h149q-11 -145 -83.5 -227t-188.5 -82q-41 0 -80.5 16.5 t-78 36t-75.5 36t-73 16.5q-31 0 -59.5 -26.5t-41.5 -80.5h-149z" /> +<glyph unicode="&#xd2;" horiz-adv-x="1630" d="M119 735q0 365 180.5 557.5t517.5 192.5t515.5 -194t178.5 -558q0 -363 -180 -558t-516 -195t-516 195t-180 560zM444 733q0 -245 93 -369t278 -124q371 0 371 493q0 494 -369 494q-185 0 -279 -124.5t-94 -369.5zM449 1886v21h342q63 -101 235 -301v-27h-202 q-63 44 -185 142.5t-190 164.5z" /> +<glyph unicode="&#xd3;" horiz-adv-x="1630" d="M119 735q0 365 180.5 557.5t517.5 192.5t515.5 -194t178.5 -558q0 -363 -180 -558t-516 -195t-516 195t-180 560zM444 733q0 -245 93 -369t278 -124q371 0 371 493q0 494 -369 494q-185 0 -279 -124.5t-94 -369.5zM658 1579v27q172 200 235 301h342v-21 q-52 -52 -177.5 -154.5t-196.5 -152.5h-203z" /> +<glyph unicode="&#xd4;" horiz-adv-x="1630" d="M119 735q0 365 180.5 557.5t517.5 192.5t515.5 -194t178.5 -558q0 -363 -180 -558t-516 -195t-516 195t-180 560zM444 733q0 -245 93 -369t278 -124q371 0 371 493q0 494 -369 494q-185 0 -279 -124.5t-94 -369.5zM381 1579v27q189 189 256 301h357q31 -52 107.5 -141.5 t148.5 -159.5v-27h-203q-157 93 -234 176q-78 -81 -229 -176h-203z" /> +<glyph unicode="&#xd5;" horiz-adv-x="1630" d="M119 735q0 365 180.5 557.5t517.5 192.5t515.5 -194t178.5 -558q0 -363 -180 -558t-516 -195t-516 195t-180 560zM444 733q0 -245 93 -369t278 -124q371 0 371 493q0 494 -369 494q-185 0 -279 -124.5t-94 -369.5zM402 1577q11 145 82.5 227t189.5 82q41 0 80.5 -16.5 t78 -36t75.5 -35.5t73 -16q31 0 59.5 26t41.5 80h149q-11 -145 -83.5 -227t-188.5 -82q-41 0 -80.5 16.5t-78 36t-75.5 36t-73 16.5q-31 0 -59.5 -26.5t-41.5 -80.5h-149z" /> +<glyph unicode="&#xd6;" horiz-adv-x="1630" d="M119 735q0 365 180.5 557.5t517.5 192.5t515.5 -194t178.5 -558q0 -363 -180 -558t-516 -195t-516 195t-180 560zM444 733q0 -245 93 -369t278 -124q371 0 371 493q0 494 -369 494q-185 0 -279 -124.5t-94 -369.5zM474 1743q0 65 37.5 100t101.5 35q66 0 103.5 -37 t37.5 -98q0 -60 -38 -96.5t-103 -36.5q-64 0 -101.5 35t-37.5 98zM877 1743q0 70 40.5 102.5t100.5 32.5q65 0 103.5 -36t38.5 -99q0 -61 -39 -97t-103 -36q-60 0 -100.5 32.5t-40.5 100.5z" /> +<glyph unicode="&#xd7;" d="M129 1024l152 154l301 -299l305 299l153 -150l-305 -305l301 -303l-149 -152l-305 301l-301 -299l-150 152l297 301z" /> +<glyph unicode="&#xd8;" horiz-adv-x="1630" d="M119 735q0 365 180.5 557.5t517.5 192.5q198 0 344 -70l84 125l160 -104l-88 -131q194 -194 194 -572q0 -363 -180 -558t-516 -195q-197 0 -336 65l-90 -135l-162 108l90 136q-198 194 -198 581zM444 733q0 -191 56 -307l506 756q-84 45 -189 45q-185 0 -279 -124.5 t-94 -369.5zM635 279q76 -39 180 -39q371 0 371 493q0 180 -51 297z" /> +<glyph unicode="&#xd9;" horiz-adv-x="1548" d="M174 520v942h309v-895q0 -169 68 -248t225 -79q152 0 220.5 79.5t68.5 249.5v893h309v-946q0 -162 -72.5 -284t-209.5 -187t-324 -65q-282 0 -438 144.5t-156 395.5zM375 1886v21h342q63 -101 235 -301v-27h-202q-63 44 -185 142.5t-190 164.5z" /> +<glyph unicode="&#xda;" horiz-adv-x="1548" d="M174 520v942h309v-895q0 -169 68 -248t225 -79q152 0 220.5 79.5t68.5 249.5v893h309v-946q0 -162 -72.5 -284t-209.5 -187t-324 -65q-282 0 -438 144.5t-156 395.5zM602 1579v27q172 200 235 301h342v-21q-52 -52 -177.5 -154.5t-196.5 -152.5h-203z" /> +<glyph unicode="&#xdb;" horiz-adv-x="1548" d="M174 520v942h309v-895q0 -169 68 -248t225 -79q152 0 220.5 79.5t68.5 249.5v893h309v-946q0 -162 -72.5 -284t-209.5 -187t-324 -65q-282 0 -438 144.5t-156 395.5zM340 1579v27q189 189 256 301h357q31 -52 107.5 -141.5t148.5 -159.5v-27h-203q-157 93 -234 176 q-78 -81 -229 -176h-203z" /> +<glyph unicode="&#xdc;" horiz-adv-x="1548" d="M174 520v942h309v-895q0 -169 68 -248t225 -79q152 0 220.5 79.5t68.5 249.5v893h309v-946q0 -162 -72.5 -284t-209.5 -187t-324 -65q-282 0 -438 144.5t-156 395.5zM433 1743q0 65 37.5 100t101.5 35q66 0 103.5 -37t37.5 -98q0 -60 -38 -96.5t-103 -36.5 q-64 0 -101.5 35t-37.5 98zM836 1743q0 70 40.5 102.5t100.5 32.5q65 0 103.5 -36t38.5 -99q0 -61 -39 -97t-103 -36q-60 0 -100.5 32.5t-40.5 100.5z" /> +<glyph unicode="&#xdd;" horiz-adv-x="1278" d="M0 1462h336l303 -602l305 602h334l-485 -893v-569h-308v559zM461 1579v27q172 200 235 301h342v-21q-52 -52 -177.5 -154.5t-196.5 -152.5h-203z" /> +<glyph unicode="&#xde;" horiz-adv-x="1286" d="M184 0v1462h310v-229h178q254 0 388 -119t134 -344q0 -229 -142.5 -353t-404.5 -124h-153v-293h-310zM494 543h100q145 0 216 52.5t71 174.5q0 107 -63.5 159t-199.5 52h-124v-438z" /> +<glyph unicode="&#xdf;" horiz-adv-x="1456" d="M160 0v1139q0 201 146.5 314.5t404.5 113.5q244 0 391 -88.5t147 -237.5q0 -64 -21 -112.5t-53 -86.5t-69 -67t-69 -53t-53 -45t-21 -43q0 -27 26.5 -53t92.5 -66q146 -91 198.5 -140t78 -110t25.5 -139q0 -172 -116.5 -259t-343.5 -87q-99 0 -171 14.5t-132 48.5v242 q53 -36 135.5 -61t146.5 -25q168 0 168 123q0 41 -16 66.5t-57 55.5t-115 72q-126 72 -175 131.5t-49 140.5q0 64 35 117t105 102q77 55 108 95t31 86q0 60 -63.5 100.5t-163.5 40.5q-116 0 -181 -52.5t-65 -148.5v-1128h-305z" /> +<glyph unicode="&#xe0;" horiz-adv-x="1237" d="M86 334q0 178 124.5 262.5t375.5 93.5l194 6v49q0 170 -174 170q-134 0 -315 -81l-101 206q193 101 428 101q225 0 345 -98t120 -298v-745h-213l-59 152h-8q-77 -97 -158.5 -134.5t-212.5 -37.5q-161 0 -253.5 92t-92.5 262zM399 332q0 -129 148 -129q106 0 169.5 61 t63.5 162v92l-118 -4q-133 -4 -198 -48t-65 -134zM239 1548v21h342q63 -101 235 -301v-27h-202q-63 44 -185 142.5t-190 164.5z" /> +<glyph unicode="&#xe1;" horiz-adv-x="1237" d="M86 334q0 178 124.5 262.5t375.5 93.5l194 6v49q0 170 -174 170q-134 0 -315 -81l-101 206q193 101 428 101q225 0 345 -98t120 -298v-745h-213l-59 152h-8q-77 -97 -158.5 -134.5t-212.5 -37.5q-161 0 -253.5 92t-92.5 262zM399 332q0 -129 148 -129q106 0 169.5 61 t63.5 162v92l-118 -4q-133 -4 -198 -48t-65 -134zM441 1241v27q172 200 235 301h342v-21q-52 -52 -177.5 -154.5t-196.5 -152.5h-203z" /> +<glyph unicode="&#xe2;" horiz-adv-x="1237" d="M86 334q0 178 124.5 262.5t375.5 93.5l194 6v49q0 170 -174 170q-134 0 -315 -81l-101 206q193 101 428 101q225 0 345 -98t120 -298v-745h-213l-59 152h-8q-77 -97 -158.5 -134.5t-212.5 -37.5q-161 0 -253.5 92t-92.5 262zM399 332q0 -129 148 -129q106 0 169.5 61 t63.5 162v92l-118 -4q-133 -4 -198 -48t-65 -134zM177 1240v27q189 189 256 301h357q31 -52 107.5 -141.5t148.5 -159.5v-27h-203q-157 93 -234 176q-78 -81 -229 -176h-203z" /> +<glyph unicode="&#xe3;" horiz-adv-x="1237" d="M86 334q0 178 124.5 262.5t375.5 93.5l194 6v49q0 170 -174 170q-134 0 -315 -81l-101 206q193 101 428 101q225 0 345 -98t120 -298v-745h-213l-59 152h-8q-77 -97 -158.5 -134.5t-212.5 -37.5q-161 0 -253.5 92t-92.5 262zM399 332q0 -129 148 -129q106 0 169.5 61 t63.5 162v92l-118 -4q-133 -4 -198 -48t-65 -134zM217 1239q11 145 82.5 227t189.5 82q41 0 80.5 -16.5t78 -36t75.5 -35.5t73 -16q31 0 59.5 26t41.5 80h149q-11 -145 -83.5 -227t-188.5 -82q-41 0 -80.5 16.5t-78 36t-75.5 36t-73 16.5q-31 0 -59.5 -26.5t-41.5 -80.5 h-149z" /> +<glyph unicode="&#xe4;" horiz-adv-x="1237" d="M86 334q0 178 124.5 262.5t375.5 93.5l194 6v49q0 170 -174 170q-134 0 -315 -81l-101 206q193 101 428 101q225 0 345 -98t120 -298v-745h-213l-59 152h-8q-77 -97 -158.5 -134.5t-212.5 -37.5q-161 0 -253.5 92t-92.5 262zM399 332q0 -129 148 -129q106 0 169.5 61 t63.5 162v92l-118 -4q-133 -4 -198 -48t-65 -134zM285 1405q0 65 37.5 100t101.5 35q66 0 103.5 -37t37.5 -98q0 -60 -38 -96.5t-103 -36.5q-64 0 -101.5 35t-37.5 98zM688 1405q0 70 40.5 102.5t100.5 32.5q65 0 103.5 -36t38.5 -99q0 -61 -39 -97t-103 -36 q-60 0 -100.5 32.5t-40.5 100.5z" /> +<glyph unicode="&#xe5;" horiz-adv-x="1237" d="M86 334q0 178 124.5 262.5t375.5 93.5l194 6v49q0 170 -174 170q-134 0 -315 -81l-101 206q193 101 428 101q225 0 345 -98t120 -298v-745h-213l-59 152h-8q-77 -97 -158.5 -134.5t-212.5 -37.5q-161 0 -253.5 92t-92.5 262zM399 332q0 -129 148 -129q106 0 169.5 61 t63.5 162v92l-118 -4q-133 -4 -198 -48t-65 -134zM381 1477q0 108 67.5 172.5t180.5 64.5q110 0 182 -66t72 -169q0 -108 -71 -174t-183 -66t-180 64t-68 174zM533 1477q0 -45 24 -71t72 -26q42 0 69 26t27 71t-27 70.5t-69 25.5t-69 -25.5t-27 -70.5z" /> +<glyph unicode="&#xe6;" horiz-adv-x="1878" d="M86 334q0 178 121 262.5t362 93.5l191 6v84q0 69 -44.5 102t-121.5 33q-140 0 -305 -77l-99 202q189 101 422 101q227 0 342 -131q66 64 152.5 96.5t206.5 32.5q221 0 349 -137.5t128 -370.5v-148h-723q5 -130 77 -203t202 -73q196 0 380 88v-236q-79 -39 -171 -59 t-226 -20q-137 0 -249.5 50.5t-184.5 155.5q-98 -117 -196.5 -161.5t-256.5 -44.5q-161 0 -258.5 94.5t-97.5 259.5zM399 332q0 -129 140 -129q101 0 161 61t60 162v92l-113 -4q-124 -4 -186 -47.5t-62 -134.5zM1073 686h430q-2 112 -55 174t-141 62q-217 0 -234 -236z" /> +<glyph unicode="&#xe7;" horiz-adv-x="1053" d="M92 553q0 285 142 435.5t407 150.5q194 0 348 -76l-90 -236q-72 29 -134 47.5t-124 18.5q-238 0 -238 -338q0 -328 238 -328q88 0 163 23.5t150 73.5v-261q-74 -47 -149.5 -65t-190.5 -18q-522 0 -522 573zM350 -303q27 -7 72.5 -14t70.5 -7q72 0 72 62q0 83 -166 108 l78 154h193l-27 -61q74 -24 118 -74.5t44 -114.5q0 -128 -75.5 -185t-233.5 -57q-78 0 -146 21v168z" /> +<glyph unicode="&#xe8;" horiz-adv-x="1210" d="M92 551q0 281 140.5 434.5t388.5 153.5q237 0 369 -135t132 -373v-148h-721q5 -130 77 -203t202 -73q101 0 191 21t188 67v-236q-80 -40 -171 -59.5t-222 -19.5q-270 0 -422 149t-152 422zM408 686h428q-2 113 -59 174.5t-154 61.5t-152 -61.5t-63 -174.5zM245 1548v21 h342q63 -101 235 -301v-27h-202q-63 44 -185 142.5t-190 164.5z" /> +<glyph unicode="&#xe9;" horiz-adv-x="1210" d="M92 551q0 281 140.5 434.5t388.5 153.5q237 0 369 -135t132 -373v-148h-721q5 -130 77 -203t202 -73q101 0 191 21t188 67v-236q-80 -40 -171 -59.5t-222 -19.5q-270 0 -422 149t-152 422zM408 686h428q-2 113 -59 174.5t-154 61.5t-152 -61.5t-63 -174.5zM447 1241v27 q172 200 235 301h342v-21q-52 -52 -177.5 -154.5t-196.5 -152.5h-203z" /> +<glyph unicode="&#xea;" horiz-adv-x="1210" d="M92 551q0 281 140.5 434.5t388.5 153.5q237 0 369 -135t132 -373v-148h-721q5 -130 77 -203t202 -73q101 0 191 21t188 67v-236q-80 -40 -171 -59.5t-222 -19.5q-270 0 -422 149t-152 422zM408 686h428q-2 113 -59 174.5t-154 61.5t-152 -61.5t-63 -174.5zM194 1241v27 q189 189 256 301h357q31 -52 107.5 -141.5t148.5 -159.5v-27h-203q-157 93 -234 176q-78 -81 -229 -176h-203z" /> +<glyph unicode="&#xeb;" horiz-adv-x="1210" d="M92 551q0 281 140.5 434.5t388.5 153.5q237 0 369 -135t132 -373v-148h-721q5 -130 77 -203t202 -73q101 0 191 21t188 67v-236q-80 -40 -171 -59.5t-222 -19.5q-270 0 -422 149t-152 422zM408 686h428q-2 113 -59 174.5t-154 61.5t-152 -61.5t-63 -174.5zM297 1405 q0 65 37.5 100t101.5 35q66 0 103.5 -37t37.5 -98q0 -60 -38 -96.5t-103 -36.5q-64 0 -101.5 35t-37.5 98zM700 1405q0 70 40.5 102.5t100.5 32.5q65 0 103.5 -36t38.5 -99q0 -61 -39 -97t-103 -36q-60 0 -100.5 32.5t-40.5 100.5z" /> +<glyph unicode="&#xec;" horiz-adv-x="625" d="M160 0v1118h305v-1118h-305zM-101 1548v21h342q63 -101 235 -301v-27h-202q-63 44 -185 142.5t-190 164.5z" /> +<glyph unicode="&#xed;" horiz-adv-x="625" d="M160 0v1118h305v-1118h-305zM145 1241v27q172 200 235 301h342v-21q-52 -52 -177.5 -154.5t-196.5 -152.5h-203z" /> +<glyph unicode="&#xee;" horiz-adv-x="625" d="M160 0v1118h305v-1118h-305zM-122 1241v27q189 189 256 301h357q31 -52 107.5 -141.5t148.5 -159.5v-27h-203q-157 93 -234 176q-78 -81 -229 -176h-203z" /> +<glyph unicode="&#xef;" horiz-adv-x="625" d="M160 0v1118h305v-1118h-305zM-29 1405q0 65 37.5 100t101.5 35q66 0 103.5 -37t37.5 -98q0 -60 -38 -96.5t-103 -36.5q-64 0 -101.5 35t-37.5 98zM374 1405q0 70 40.5 102.5t100.5 32.5q65 0 103.5 -36t38.5 -99q0 -61 -39 -97t-103 -36q-60 0 -100.5 32.5t-40.5 100.5z " /> +<glyph unicode="&#xf0;" horiz-adv-x="1268" d="M92 489q0 233 130 369.5t351 136.5q205 0 275 -98l8 4q-67 162 -192 281l-230 -142l-100 156l176 107q-80 53 -152 92l101 176q144 -65 258 -141l225 139l100 -154l-170 -104q156 -143 230 -324.5t74 -413.5q0 -280 -145 -436.5t-400 -156.5q-245 0 -392 137t-147 372z M403 487q0 -140 60 -211t172 -71q123 0 176 82t53 245q0 108 -61 173t-168 65q-121 0 -176.5 -68.5t-55.5 -214.5z" /> +<glyph unicode="&#xf1;" horiz-adv-x="1346" d="M160 0v1118h233l41 -143h17q51 81 140.5 122.5t203.5 41.5q195 0 296 -105.5t101 -304.5v-729h-305v653q0 121 -43 181.5t-137 60.5q-128 0 -185 -85.5t-57 -283.5v-526h-305zM258 1239q11 145 82.5 227t189.5 82q41 0 80.5 -16.5t78 -36t75.5 -35.5t73 -16q31 0 59.5 26 t41.5 80h149q-11 -145 -83.5 -227t-188.5 -82q-41 0 -80.5 16.5t-78 36t-75.5 36t-73 16.5q-31 0 -59.5 -26.5t-41.5 -80.5h-149z" /> +<glyph unicode="&#xf2;" horiz-adv-x="1268" d="M92 561q0 274 143 426t402 152q161 0 284 -70t189 -201t66 -307q0 -273 -144 -427t-401 -154q-161 0 -284 70.5t-189 202.5t-66 308zM403 561q0 -166 54.5 -251t177.5 -85q122 0 175.5 84.5t53.5 251.5q0 166 -54 249t-177 83q-122 0 -176 -82.5t-54 -249.5zM237 1548v21 h342q63 -101 235 -301v-27h-202q-63 44 -185 142.5t-190 164.5z" /> +<glyph unicode="&#xf3;" horiz-adv-x="1268" d="M92 561q0 274 143 426t402 152q161 0 284 -70t189 -201t66 -307q0 -273 -144 -427t-401 -154q-161 0 -284 70.5t-189 202.5t-66 308zM403 561q0 -166 54.5 -251t177.5 -85q122 0 175.5 84.5t53.5 251.5q0 166 -54 249t-177 83q-122 0 -176 -82.5t-54 -249.5zM467 1241v27 q172 200 235 301h342v-21q-52 -52 -177.5 -154.5t-196.5 -152.5h-203z" /> +<glyph unicode="&#xf4;" horiz-adv-x="1268" d="M92 561q0 274 143 426t402 152q161 0 284 -70t189 -201t66 -307q0 -273 -144 -427t-401 -154q-161 0 -284 70.5t-189 202.5t-66 308zM403 561q0 -166 54.5 -251t177.5 -85q122 0 175.5 84.5t53.5 251.5q0 166 -54 249t-177 83q-122 0 -176 -82.5t-54 -249.5zM198 1241v27 q189 189 256 301h357q31 -52 107.5 -141.5t148.5 -159.5v-27h-203q-157 93 -234 176q-78 -81 -229 -176h-203z" /> +<glyph unicode="&#xf5;" horiz-adv-x="1268" d="M92 561q0 274 143 426t402 152q161 0 284 -70t189 -201t66 -307q0 -273 -144 -427t-401 -154q-161 0 -284 70.5t-189 202.5t-66 308zM403 561q0 -166 54.5 -251t177.5 -85q122 0 175.5 84.5t53.5 251.5q0 166 -54 249t-177 83q-122 0 -176 -82.5t-54 -249.5zM219 1239 q11 145 82.5 227t189.5 82q41 0 80.5 -16.5t78 -36t75.5 -35.5t73 -16q31 0 59.5 26t41.5 80h149q-11 -145 -83.5 -227t-188.5 -82q-41 0 -80.5 16.5t-78 36t-75.5 36t-73 16.5q-31 0 -59.5 -26.5t-41.5 -80.5h-149z" /> +<glyph unicode="&#xf6;" horiz-adv-x="1268" d="M92 561q0 274 143 426t402 152q161 0 284 -70t189 -201t66 -307q0 -273 -144 -427t-401 -154q-161 0 -284 70.5t-189 202.5t-66 308zM403 561q0 -166 54.5 -251t177.5 -85q122 0 175.5 84.5t53.5 251.5q0 166 -54 249t-177 83q-122 0 -176 -82.5t-54 -249.5zM291 1405 q0 65 37.5 100t101.5 35q66 0 103.5 -37t37.5 -98q0 -60 -38 -96.5t-103 -36.5q-64 0 -101.5 35t-37.5 98zM694 1405q0 70 40.5 102.5t100.5 32.5q65 0 103.5 -36t38.5 -99q0 -61 -39 -97t-103 -36q-60 0 -100.5 32.5t-40.5 100.5z" /> +<glyph unicode="&#xf7;" d="M88 612v219h993v-219h-993zM444 373q0 76 37 113.5t103 37.5t102.5 -39t36.5 -112q0 -70 -37 -111t-102 -41t-102.5 39t-37.5 113zM444 1071q0 75 37 113.5t103 38.5q67 0 103 -40.5t36 -111.5q0 -70 -37 -110.5t-102 -40.5t-102.5 39t-37.5 112z" /> +<glyph unicode="&#xf8;" horiz-adv-x="1268" d="M92 561q0 274 143 426t402 152q132 0 248 -52l55 82l152 -108l-58 -84q142 -155 142 -416q0 -273 -144 -427t-401 -154q-126 0 -234 45l-67 -101l-154 105l68 100q-152 156 -152 432zM403 561q0 -94 19 -166l317 475q-43 23 -106 23q-122 0 -176 -82.5t-54 -249.5z M543 240q38 -15 92 -15q122 0 175.5 84.5t53.5 251.5q0 81 -12 141z" /> +<glyph unicode="&#xf9;" horiz-adv-x="1346" d="M154 389v729h305v-653q0 -121 43 -181.5t137 -60.5q128 0 185 85.5t57 283.5v526h305v-1118h-234l-41 143h-16q-49 -78 -139 -120.5t-205 -42.5q-197 0 -297 105.5t-100 303.5zM245 1548v21h342q63 -101 235 -301v-27h-202q-63 44 -185 142.5t-190 164.5z" /> +<glyph unicode="&#xfa;" horiz-adv-x="1346" d="M154 389v729h305v-653q0 -121 43 -181.5t137 -60.5q128 0 185 85.5t57 283.5v526h305v-1118h-234l-41 143h-16q-49 -78 -139 -120.5t-205 -42.5q-197 0 -297 105.5t-100 303.5zM498 1241v27q172 200 235 301h342v-21q-52 -52 -177.5 -154.5t-196.5 -152.5h-203z" /> +<glyph unicode="&#xfb;" horiz-adv-x="1346" d="M154 389v729h305v-653q0 -121 43 -181.5t137 -60.5q128 0 185 85.5t57 283.5v526h305v-1118h-234l-41 143h-16q-49 -78 -139 -120.5t-205 -42.5q-197 0 -297 105.5t-100 303.5zM235 1241v27q189 189 256 301h357q31 -52 107.5 -141.5t148.5 -159.5v-27h-203 q-157 93 -234 176q-78 -81 -229 -176h-203z" /> +<glyph unicode="&#xfc;" horiz-adv-x="1346" d="M154 389v729h305v-653q0 -121 43 -181.5t137 -60.5q128 0 185 85.5t57 283.5v526h305v-1118h-234l-41 143h-16q-49 -78 -139 -120.5t-205 -42.5q-197 0 -297 105.5t-100 303.5zM326 1405q0 65 37.5 100t101.5 35q66 0 103.5 -37t37.5 -98q0 -60 -38 -96.5t-103 -36.5 q-64 0 -101.5 35t-37.5 98zM729 1405q0 70 40.5 102.5t100.5 32.5q65 0 103.5 -36t38.5 -99q0 -61 -39 -97t-103 -36q-60 0 -100.5 32.5t-40.5 100.5z" /> +<glyph unicode="&#xfd;" horiz-adv-x="1165" d="M0 1118h334l211 -629q27 -82 37 -194h6q11 103 43 194l207 629h327l-473 -1261q-65 -175 -185.5 -262t-281.5 -87q-79 0 -155 17v242q55 -13 120 -13q81 0 141.5 49.5t94.5 149.5l18 55zM393 1241v27q172 200 235 301h342v-21q-52 -52 -177.5 -154.5t-196.5 -152.5h-203z " /> +<glyph unicode="&#xfe;" horiz-adv-x="1296" d="M160 -492v2048h305v-391l-7 -120l-7 -72h14q50 81 131 123.5t186 42.5q198 0 310 -154.5t112 -423.5q0 -273 -111.5 -427t-310.5 -154q-213 0 -317 137h-14l7 -62l7 -94v-453h-305zM465 563q0 -180 53.5 -258t169.5 -78q205 0 205 338q0 165 -50.5 247.5t-158.5 82.5 q-113 0 -165 -69.5t-54 -229.5v-33z" /> +<glyph unicode="&#xff;" horiz-adv-x="1165" d="M0 1118h334l211 -629q27 -82 37 -194h6q11 103 43 194l207 629h327l-473 -1261q-65 -175 -185.5 -262t-281.5 -87q-79 0 -155 17v242q55 -13 120 -13q81 0 141.5 49.5t94.5 149.5l18 55zM243 1405q0 65 37.5 100t101.5 35q66 0 103.5 -37t37.5 -98q0 -60 -38 -96.5 t-103 -36.5q-64 0 -101.5 35t-37.5 98zM646 1405q0 70 40.5 102.5t100.5 32.5q65 0 103.5 -36t38.5 -99q0 -61 -39 -97t-103 -36q-60 0 -100.5 32.5t-40.5 100.5z" /> +<glyph unicode="&#x131;" horiz-adv-x="625" d="M160 0v1118h305v-1118h-305z" /> +<glyph unicode="&#x152;" horiz-adv-x="1993" d="M119 735q0 363 169.5 556.5t487.5 193.5q61 0 127 -7t101 -16h868v-254h-563v-321h526v-254h-526v-377h563v-256h-873q-38 -9 -109 -14.5t-116 -5.5q-319 0 -487 197t-168 558zM438 733q0 -244 86 -368.5t250 -124.5q65 0 126 10.5t99 28.5v907q-35 19 -101.5 30 t-121.5 11q-166 0 -252 -125.5t-86 -368.5z" /> +<glyph unicode="&#x153;" horiz-adv-x="2003" d="M92 561q0 277 141.5 427.5t399.5 150.5q112 0 212 -39.5t171 -116.5q144 156 383 156q244 0 380 -135t136 -373v-148h-746v-8q7 -127 81.5 -197.5t207.5 -70.5q107 0 200 21t193 67v-236q-81 -39 -175.5 -59t-229.5 -20q-271 0 -420 155q-141 -155 -391 -155 q-162 0 -286 70t-190.5 202t-66.5 309zM403 561q0 -166 54.5 -251t177.5 -85q122 0 175.5 84.5t53.5 251.5q0 166 -54 249t-177 83q-122 0 -176 -82.5t-54 -249.5zM1178 686h450q-2 111 -60.5 173.5t-162.5 62.5q-94 0 -156 -57.5t-71 -178.5z" /> +<glyph unicode="&#x178;" horiz-adv-x="1278" d="M0 1462h336l303 -602l305 602h334l-485 -893v-569h-308v559zM297 1743q0 65 37.5 100t101.5 35q66 0 103.5 -37t37.5 -98q0 -60 -38 -96.5t-103 -36.5q-64 0 -101.5 35t-37.5 98zM700 1743q0 70 40.5 102.5t100.5 32.5q65 0 103.5 -36t38.5 -99q0 -61 -39 -97t-103 -36 q-60 0 -100.5 32.5t-40.5 100.5z" /> +<glyph unicode="&#x2c6;" horiz-adv-x="1243" d="M186 1241v27q189 189 256 301h357q31 -52 107.5 -141.5t148.5 -159.5v-27h-203q-157 93 -234 176q-78 -81 -229 -176h-203z" /> +<glyph unicode="&#x2da;" horiz-adv-x="1182" d="M340 1477q0 108 67.5 172.5t180.5 64.5q110 0 182 -66t72 -169q0 -108 -71 -174t-183 -66t-180 64t-68 174zM492 1477q0 -45 24 -71t72 -26q42 0 69 26t27 71t-27 70.5t-69 25.5t-69 -25.5t-27 -70.5z" /> +<glyph unicode="&#x2dc;" horiz-adv-x="1243" d="M207 1239q11 145 82.5 227t189.5 82q41 0 80.5 -16.5t78 -36t75.5 -35.5t73 -16q31 0 59.5 26t41.5 80h149q-11 -145 -83.5 -227t-188.5 -82q-41 0 -80.5 16.5t-78 36t-75.5 36t-73 16.5q-31 0 -59.5 -26.5t-41.5 -80.5h-149z" /> +<glyph unicode="&#x2000;" horiz-adv-x="953" /> +<glyph unicode="&#x2001;" horiz-adv-x="1907" /> +<glyph unicode="&#x2002;" horiz-adv-x="953" /> +<glyph unicode="&#x2003;" horiz-adv-x="1907" /> +<glyph unicode="&#x2004;" horiz-adv-x="635" /> +<glyph unicode="&#x2005;" horiz-adv-x="476" /> +<glyph unicode="&#x2006;" horiz-adv-x="317" /> +<glyph unicode="&#x2007;" horiz-adv-x="317" /> +<glyph unicode="&#x2008;" horiz-adv-x="238" /> +<glyph unicode="&#x2009;" horiz-adv-x="381" /> +<glyph unicode="&#x200a;" horiz-adv-x="105" /> +<glyph unicode="&#x2010;" horiz-adv-x="659" d="M61 424v250h537v-250h-537z" /> +<glyph unicode="&#x2011;" horiz-adv-x="659" d="M61 424v250h537v-250h-537z" /> +<glyph unicode="&#x2012;" horiz-adv-x="659" d="M61 424v250h537v-250h-537z" /> +<glyph unicode="&#x2013;" horiz-adv-x="1024" d="M82 436v230h860v-230h-860z" /> +<glyph unicode="&#x2014;" horiz-adv-x="2048" d="M82 436v230h1884v-230h-1884z" /> +<glyph unicode="&#x2018;" horiz-adv-x="444" d="M25 983q22 91 72.5 228.5t103.5 250.5h219q-66 -267 -101 -501h-280z" /> +<glyph unicode="&#x2019;" horiz-adv-x="444" d="M25 961q69 296 100 501h281l14 -22q-50 -197 -176 -479h-219z" /> +<glyph unicode="&#x201a;" horiz-adv-x="596" d="M63 -264q65 266 101 502h280l15 -23q-52 -202 -176 -479h-220z" /> +<glyph unicode="&#x201c;" horiz-adv-x="911" d="M25 983q22 91 72.5 228.5t103.5 250.5h219q-66 -267 -101 -501h-280zM492 983q22 91 72.5 228.5t103.5 250.5h219q-66 -267 -101 -501h-280z" /> +<glyph unicode="&#x201d;" horiz-adv-x="911" d="M25 961q69 296 100 501h281l14 -22q-50 -197 -176 -479h-219zM492 961q69 296 100 501h280l15 -22q-50 -197 -176 -479h-219z" /> +<glyph unicode="&#x201e;" horiz-adv-x="1061" d="M63 -264q65 266 101 502h280l15 -23q-52 -202 -176 -479h-220zM530 -264q65 266 101 502h280l15 -23q-52 -202 -176 -479h-220z" /> +<glyph unicode="&#x2022;" horiz-adv-x="770" d="M98 748q0 154 74 235.5t213 81.5q137 0 212 -82t75 -235q0 -152 -75.5 -235t-211.5 -83q-138 0 -212.5 83t-74.5 235z" /> +<glyph unicode="&#x2026;" horiz-adv-x="1751" d="M117 143q0 84 45 127t131 43q83 0 128.5 -44t45.5 -126q0 -79 -46 -124.5t-128 -45.5q-84 0 -130 44.5t-46 125.5zM700 143q0 84 45 127t132 43q83 0 128.5 -44t45.5 -126q0 -79 -46 -124.5t-128 -45.5q-85 0 -131 44.5t-46 125.5zM1284 143q0 84 45 127t131 43 q83 0 128.5 -44t45.5 -126q0 -79 -46 -124.5t-128 -45.5q-84 0 -130 44.5t-46 125.5z" /> +<glyph unicode="&#x202f;" horiz-adv-x="381" /> +<glyph unicode="&#x2039;" horiz-adv-x="754" d="M82 547v26l371 455l219 -119l-279 -348l279 -348l-219 -119z" /> +<glyph unicode="&#x203a;" horiz-adv-x="754" d="M82 213l278 348l-278 348l219 119l371 -455v-26l-371 -453z" /> +<glyph unicode="&#x2044;" horiz-adv-x="266" d="M-393 0l811 1462h239l-811 -1462h-239z" /> +<glyph unicode="&#x205f;" horiz-adv-x="476" /> +<glyph unicode="&#x2074;" horiz-adv-x="776" d="M12 737v154l385 577h236v-563h125v-168h-125v-151h-238v151h-383zM197 905h198v164q0 86 6 184q-9 -26 -35.5 -80t-41.5 -77z" /> +<glyph unicode="&#x20ac;" d="M66 481v178h118q-4 23 -4 62l2 53h-116v176h133q37 242 199 382.5t405 140.5q188 0 352 -82l-98 -232q-69 31 -129 48.5t-125 17.5q-122 0 -201 -70.5t-102 -204.5h403v-176h-418l-2 -35v-47l2 -33h355v-178h-338q51 -243 321 -243q143 0 275 57v-256q-116 -59 -293 -59 q-245 0 -403 133t-199 368h-137z" /> +<glyph unicode="&#x2122;" horiz-adv-x="1534" d="M16 1313v149h564v-149h-199v-572h-168v572h-197zM625 741v721h247l160 -510l170 510h240v-721h-168v408l4 121h-6l-174 -529h-142l-165 529h-7l4 -111v-418h-163z" /> +<glyph unicode="&#xe000;" horiz-adv-x="1120" d="M0 1120h1120v-1120h-1120v1120z" /> +<glyph unicode="&#xfb01;" horiz-adv-x="1417" d="M41 889v147l168 82v82q0 191 94 279t301 88q158 0 281 -47l-78 -224q-92 29 -170 29q-65 0 -94 -38.5t-29 -98.5v-70h264v-229h-264v-889h-305v889h-168zM940 1407q0 149 166 149t166 -149q0 -71 -41.5 -110.5t-124.5 -39.5q-166 0 -166 150zM953 0v1118h305v-1118h-305z " /> +<glyph unicode="&#xfb02;" horiz-adv-x="1417" d="M41 889v147l168 82v82q0 191 94 279t301 88q158 0 281 -47l-78 -224q-92 29 -170 29q-65 0 -94 -38.5t-29 -98.5v-70h264v-229h-264v-889h-305v889h-168zM953 0v1556h305v-1556h-305z" /> +<glyph unicode="&#xfb03;" horiz-adv-x="2208" d="M41 889v147l168 82v82q0 191 94 279t301 88q158 0 281 -47l-78 -224q-92 29 -170 29q-65 0 -94 -38.5t-29 -98.5v-70h264v-229h-264v-889h-305v889h-168zM834 889v147l168 82v82q0 191 94 279t301 88q158 0 281 -47l-78 -224q-92 29 -170 29q-65 0 -94 -38.5t-29 -98.5 v-70h264v-229h-264v-889h-305v889h-168zM1730 1407q0 149 166 149t166 -149q0 -71 -41.5 -110.5t-124.5 -39.5q-166 0 -166 150zM1743 0v1118h305v-1118h-305z" /> +<glyph unicode="&#xfb04;" horiz-adv-x="2208" d="M41 889v147l168 82v82q0 191 94 279t301 88q158 0 281 -47l-78 -224q-92 29 -170 29q-65 0 -94 -38.5t-29 -98.5v-70h264v-229h-264v-889h-305v889h-168zM834 889v147l168 82v82q0 191 94 279t301 88q158 0 281 -47l-78 -224q-92 29 -170 29q-65 0 -94 -38.5t-29 -98.5 v-70h264v-229h-264v-889h-305v889h-168zM1743 0v1556h305v-1556h-305z" /> +</font> +</defs></svg> +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Bold-webfont.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.svg b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.svg @@ -0,0 +1,251 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata> +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom +</metadata> +<defs> +<font id="OpenSansBoldItalic" horiz-adv-x="1128" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="&#x09;" horiz-adv-x="532" /> +<glyph unicode="&#xa0;" horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="586" d="M25 115q0 90 53.5 144t150.5 54q68 0 109 -38t41 -107q0 -87 -55 -141t-144 -54q-73 0 -114 37.5t-41 104.5zM150 485l157 977h340l-256 -977h-241z" /> +<glyph unicode="&#x22;" horiz-adv-x="928" d="M201 934l71 528h277l-152 -528h-196zM604 934l74 528h276l-151 -528h-199z" /> +<glyph unicode="#" horiz-adv-x="1323" d="M41 408l18 206h277l70 232h-252l18 209h289l119 407h217l-117 -407h199l116 407h215l-116 -407h239l-18 -209h-279l-69 -232h258l-19 -206h-297l-116 -408h-220l117 408h-194l-115 -408h-215l113 408h-238zM553 614h197l69 232h-196z" /> +<glyph unicode="$" d="M51 168v266q198 -107 404 -117l71 322q-163 61 -241 151t-78 214q0 173 127 279.5t350 121.5l35 151h139l-33 -151q166 -22 295 -90l-106 -232q-132 65 -242 74l-63 -299q131 -51 195 -99.5t97 -113t33 -149.5q0 -184 -125.5 -291.5t-367.5 -124.5l-39 -199h-140l44 201 q-209 12 -355 86zM502 1022q0 -79 80 -111l51 246q-62 -7 -96.5 -41t-34.5 -94zM594 322q63 9 102 45t39 98q0 46 -24.5 75.5t-59.5 43.5z" /> +<glyph unicode="%" horiz-adv-x="1753" d="M115 885q0 169 55.5 311.5t148.5 214.5t216 72q137 0 211.5 -80t74.5 -238q0 -166 -56 -310t-151 -217t-217 -73q-139 0 -210.5 83.5t-71.5 236.5zM231 0l1088 1462h235l-1083 -1462h-240zM360 868q0 -96 56 -96q65 0 112 131t47 275q0 96 -57 96q-63 0 -110.5 -128.5 t-47.5 -277.5zM973 283q0 177 53 322.5t148 219.5t219 74q137 0 211.5 -78.5t74.5 -230.5q0 -167 -54 -313.5t-148 -220.5t-215 -74q-144 0 -216.5 78.5t-72.5 222.5zM1219 285q0 -97 55 -97q41 0 77 55t59.5 154.5t23.5 196.5q0 96 -58 96q-39 0 -75 -56t-59 -154t-23 -195 z" /> +<glyph unicode="&#x26;" horiz-adv-x="1450" d="M68 358q0 145 78.5 248.5t273.5 200.5q-76 130 -76 258q0 195 117.5 307.5t316.5 112.5q169 0 266 -82.5t97 -224.5q0 -280 -365 -426l195 -263q44 57 80.5 121.5t78.5 173.5h300q-133 -313 -310 -497l205 -287h-350l-72 98q-175 -118 -403 -118q-209 0 -320.5 97.5 t-111.5 280.5zM383 387q0 -65 45.5 -108t116.5 -43q115 0 221 59l-225 328q-88 -51 -123 -104.5t-35 -131.5zM621 1085q0 -46 12 -92t29 -73q113 59 155.5 111t42.5 112q0 57 -30 82.5t-70 25.5q-66 0 -102.5 -46.5t-36.5 -119.5z" /> +<glyph unicode="'" horiz-adv-x="522" d="M201 934l71 528h277l-152 -528h-196z" /> +<glyph unicode="(" horiz-adv-x="694" d="M74 281q0 339 122.5 626.5t381.5 554.5h262q-255 -278 -377.5 -573.5t-122.5 -618.5q0 -308 117 -594h-234q-149 266 -149 605z" /> +<glyph unicode=")" horiz-adv-x="694" d="M-147 -324q499 545 499 1192q0 307 -116 594h233q149 -264 149 -604q0 -342 -124 -630.5t-379 -551.5h-262z" /> +<glyph unicode="*" horiz-adv-x="1116" d="M172 1141l86 237l338 -174l33 369l256 -51l-113 -353l387 29l-18 -254l-338 43l160 -336l-246 -73l-90 337l-197 -278l-207 164l275 248z" /> +<glyph unicode="+" d="M109 612v219h366v369h219v-369h367v-219h-367v-364h-219v364h-366z" /> +<glyph unicode="," horiz-adv-x="569" d="M-102 -264q74 167 194 502h285l8 -23q-118 -255 -262 -479h-225z" /> +<glyph unicode="-" horiz-adv-x="659" d="M41 424l53 250h524l-53 -250h-524z" /> +<glyph unicode="." horiz-adv-x="584" d="M25 115q0 90 53.5 144t150.5 54q68 0 109 -38t41 -107q0 -87 -55 -141t-144 -54q-73 0 -114 37.5t-41 104.5z" /> +<glyph unicode="/" horiz-adv-x="862" d="M-90 0l809 1462h295l-809 -1462h-295z" /> +<glyph unicode="0" d="M66 467q0 297 84 537t228 360.5t333 120.5q399 0 399 -473q0 -470 -168.5 -751t-472.5 -281q-198 0 -300.5 122t-102.5 365zM369 461q0 -115 27.5 -173.5t97.5 -58.5q81 0 150.5 106t116 301t46.5 386q0 111 -30.5 162t-92.5 51q-80 0 -149.5 -104t-117.5 -302t-48 -368z " /> +<glyph unicode="1" d="M182 1114l566 348h249l-309 -1462h-305l180 829q35 152 76 287q-9 -8 -61.5 -47t-262.5 -170z" /> +<glyph unicode="2" d="M-49 0l43 213l477 424q180 159 248.5 254.5t68.5 179.5q0 75 -41 114.5t-110 39.5q-66 0 -135.5 -33.5t-171.5 -118.5l-146 203q132 112 252 159.5t250 47.5q190 0 301 -98t111 -259q0 -107 -41 -201t-122.5 -188t-266.5 -245l-269 -222v-10h568l-54 -260h-962z" /> +<glyph unicode="3" d="M14 59v267q84 -50 182 -75.5t191 -25.5q158 0 243 63.5t85 176.5q0 172 -258 172h-138l46 221h73q167 0 263 62t96 172q0 67 -43 104t-121 37q-134 0 -287 -100l-127 204q124 81 232.5 113.5t246.5 32.5q190 0 298 -90.5t108 -243.5q0 -156 -94.5 -262t-261.5 -135v-4 q131 -26 198.5 -106.5t67.5 -201.5q0 -133 -74 -238t-212 -163.5t-327 -58.5q-239 0 -387 79z" /> +<glyph unicode="4" d="M-25 303l48 234l770 925h311l-195 -919h170l-51 -240h-170l-63 -303h-293l63 303h-590zM305 543h311l58 248q12 58 40 164t42 141h-6q-35 -63 -132 -181z" /> +<glyph unicode="5" d="M27 61v269q174 -99 352 -99q154 0 241 71t87 194q0 94 -57.5 141t-166.5 47q-102 0 -213 -33l-104 78l207 733h755l-55 -262h-489l-88 -293q72 15 127 15q183 0 289 -103t106 -287q0 -167 -71.5 -292t-208.5 -192.5t-330 -67.5q-117 0 -218.5 23t-162.5 58z" /> +<glyph unicode="6" d="M88 469q0 202 61 395.5t167.5 335t256.5 213.5t357 72q125 0 223 -27l-51 -246q-84 25 -191 25q-194 0 -313.5 -108t-185.5 -345h4q115 166 311 166q157 0 242.5 -97t85.5 -273q0 -169 -71 -313.5t-190.5 -215.5t-277.5 -71q-212 0 -320 127t-108 362zM383 422 q0 -91 40 -143t107 -52q99 0 161.5 94t62.5 236q0 71 -33.5 113.5t-102.5 42.5q-60 0 -114.5 -35.5t-87.5 -95.5t-33 -160z" /> +<glyph unicode="7" d="M78 0l737 1202h-629l56 260h975l-41 -194l-752 -1268h-346z" /> +<glyph unicode="8" d="M55 350q0 298 348 426q-165 132 -165 299q0 119 58 212.5t168 145.5t257 52q123 0 215.5 -42t141 -118t48.5 -174q0 -134 -80.5 -233.5t-230.5 -151.5q217 -141 217 -365q0 -122 -63.5 -218.5t-181 -149.5t-273.5 -53q-214 0 -336.5 100t-122.5 270zM352 383 q0 -81 50 -128.5t135 -47.5q93 0 147.5 53.5t54.5 138.5q0 73 -36.5 131.5t-120.5 112.5q-116 -45 -173 -107t-57 -153zM528 1094q0 -132 123 -201q185 72 185 221q0 68 -39.5 107t-102.5 39q-76 0 -121 -46.5t-45 -119.5z" /> +<glyph unicode="9" d="M86 12v256q111 -41 227 -41q121 0 207.5 49t144 138.5t99.5 257.5h-4q-111 -158 -295 -158q-163 0 -252.5 103.5t-89.5 285.5q0 166 73 305.5t196 208t286 68.5q203 0 308.5 -123t105.5 -361q0 -280 -99 -533t-264 -370.5t-403 -117.5q-128 0 -240 32zM424 928 q0 -87 37.5 -131.5t105.5 -44.5q60 0 111.5 36.5t82 100t30.5 158.5q0 84 -35.5 137t-110.5 53q-65 0 -115.5 -42t-78 -114t-27.5 -153z" /> +<glyph unicode=":" horiz-adv-x="584" d="M25 115q0 90 53.5 144t150.5 54q68 0 109 -38t41 -107q0 -87 -55 -141t-144 -54q-73 0 -114 37.5t-41 104.5zM207 940q0 92 55.5 145.5t149.5 53.5q68 0 108.5 -38.5t40.5 -107.5q0 -86 -54.5 -140t-144.5 -54q-72 0 -113.5 36.5t-41.5 104.5z" /> +<glyph unicode=";" horiz-adv-x="584" d="M-102 -264q74 167 194 502h285l8 -23q-118 -255 -262 -479h-225zM207 940q0 92 55.5 145.5t149.5 53.5q68 0 108.5 -38.5t40.5 -107.5q0 -86 -54.5 -140t-144.5 -54q-72 0 -113.5 36.5t-41.5 104.5z" /> +<glyph unicode="&#x3c;" d="M109 641v143l952 496v-240l-643 -317l643 -281v-239z" /> +<glyph unicode="=" d="M109 418v219h952v-219h-952zM109 807v217h952v-217h-952z" /> +<glyph unicode="&#x3e;" d="M109 203v239l643 281l-643 317v240l952 -496v-143z" /> +<glyph unicode="?" horiz-adv-x="940" d="M166 115q0 91 55 144.5t150 53.5q68 0 108.5 -38t40.5 -107q0 -87 -55 -141t-143 -54q-74 0 -115 38t-41 104zM178 1358q230 125 445 125q177 0 280 -87.5t103 -244.5q0 -83 -28.5 -149.5t-82.5 -123t-190 -147.5q-64 -43 -96.5 -73t-52.5 -64.5t-38 -108.5h-258l14 78 q19 103 73.5 177t172.5 155q124 84 157.5 127t33.5 96q0 119 -133 119q-50 0 -106.5 -16t-201.5 -84z" /> +<glyph unicode="@" horiz-adv-x="1753" d="M92 500q0 279 120.5 497t343 341.5t497.5 123.5q318 0 499 -163.5t181 -458.5q0 -173 -64 -321t-177.5 -231t-254.5 -83q-88 0 -144.5 38.5t-72.5 108.5h-6q-50 -77 -113 -112t-147 -35q-127 0 -198 79.5t-71 229.5q0 147 67.5 276.5t187.5 205t268 75.5q185 0 327 -55 l-106 -420q-11 -44 -19 -76.5t-8 -64.5q0 -68 58 -68q66 0 124 64t92.5 171t34.5 214q0 213 -123.5 325.5t-359.5 112.5q-203 0 -366.5 -94t-255 -266t-91.5 -392q0 -243 134 -380.5t376 -137.5q117 0 219.5 20t221.5 66v-186q-230 -90 -465 -90q-217 0 -378 85.5 t-246 241.5t-85 359zM713 526q0 -65 24.5 -102t69.5 -37q141 0 213 270l57 222q-36 10 -82 10q-82 0 -145.5 -51.5t-100 -137t-36.5 -174.5z" /> +<glyph unicode="A" horiz-adv-x="1286" d="M-123 0l766 1468h373l147 -1468h-297l-24 348h-473l-172 -348h-320zM494 608h333l-26 350q-10 131 -10 253v36q-44 -120 -109 -254z" /> +<glyph unicode="B" horiz-adv-x="1270" d="M53 0l309 1462h426q229 0 346 -81.5t117 -243.5q0 -150 -83 -247.5t-236 -129.5v-6q100 -26 159.5 -96.5t59.5 -180.5q0 -229 -153 -353t-423 -124h-522zM412 256h180q117 0 183.5 58t66.5 161q0 162 -183 162h-165zM545 883h149q121 0 181.5 48.5t60.5 139.5 q0 137 -170 137h-152z" /> +<glyph unicode="C" horiz-adv-x="1253" d="M123 553q0 262 104 482.5t278 335t400 114.5q125 0 222 -22.5t208 -82.5l-118 -250q-106 59 -175 78t-137 19q-132 0 -237.5 -81t-169.5 -238.5t-64 -338.5q0 -167 68.5 -248t218.5 -81q146 0 338 77v-260q-199 -77 -400 -77q-254 0 -395 149.5t-141 423.5z" /> +<glyph unicode="D" horiz-adv-x="1386" d="M53 0l309 1462h396q270 0 417.5 -143t147.5 -410q0 -280 -98 -486.5t-283.5 -314.5t-437.5 -108h-451zM412 256h106q148 0 258 76t172 223.5t62 337.5q0 154 -72.5 234.5t-208.5 80.5h-115z" /> +<glyph unicode="E" horiz-adv-x="1110" d="M53 0l309 1462h818l-54 -254h-512l-67 -321h477l-55 -254h-477l-80 -377h512l-54 -256h-817z" /> +<glyph unicode="F" horiz-adv-x="1087" d="M53 0l309 1462h814l-54 -254h-508l-79 -377h473l-56 -253h-473l-121 -578h-305z" /> +<glyph unicode="G" horiz-adv-x="1413" d="M123 549q0 268 107 484.5t301 334t448 117.5q218 0 410 -99l-115 -251q-74 40 -148 64t-161 24q-153 0 -273.5 -83t-189 -236.5t-68.5 -330.5q0 -172 72.5 -252.5t222.5 -80.5q76 0 170 24l66 299h-267l56 258h563l-162 -762q-134 -46 -248.5 -62.5t-242.5 -16.5 q-259 0 -400 147t-141 422z" /> +<glyph unicode="H" horiz-adv-x="1434" d="M53 0l309 1462h306l-121 -573h471l121 573h305l-309 -1462h-306l134 631h-471l-134 -631h-305z" /> +<glyph unicode="I" horiz-adv-x="659" d="M53 0l312 1462h305l-312 -1462h-305z" /> +<glyph unicode="J" horiz-adv-x="678" d="M-322 -150q88 -20 164 -20q99 0 160.5 60.5t89.5 191.5l293 1380h305l-303 -1423q-52 -245 -175.5 -357t-346.5 -112q-94 0 -187 27v253z" /> +<glyph unicode="K" horiz-adv-x="1255" d="M53 0l309 1462h306l-152 -702l158 205l409 497h361l-594 -700l291 -762h-338l-211 592l-125 -70l-109 -522h-305z" /> +<glyph unicode="L" horiz-adv-x="1061" d="M53 0l309 1462h306l-256 -1206h512l-54 -256h-817z" /> +<glyph unicode="M" horiz-adv-x="1802" d="M53 0l309 1462h404l68 -1093h4l551 1093h423l-309 -1462h-280l145 692q53 247 105 441h-5l-569 -1133h-281l-61 1133h-4q-11 -88 -38 -231t-187 -902h-275z" /> +<glyph unicode="N" horiz-adv-x="1546" d="M53 0l309 1462h357l340 -1077h4q12 76 39 217t180 860h274l-309 -1462h-342l-356 1106h-6l-4 -32q-32 -216 -66 -386l-145 -688h-275z" /> +<glyph unicode="O" horiz-adv-x="1495" d="M123 537q0 265 99 487.5t273 341.5t402 119q255 0 395 -144t140 -403q0 -283 -99 -506.5t-271 -337.5t-396 -114q-256 0 -399.5 147.5t-143.5 409.5zM434 537q0 -147 66.5 -222t187.5 -75t220.5 87t155.5 246t56 357q0 142 -65 219.5t-183 77.5q-121 0 -222 -91.5 t-158.5 -251.5t-57.5 -347z" /> +<glyph unicode="P" horiz-adv-x="1188" d="M53 0l309 1462h338q242 0 366 -106.5t124 -319.5q0 -241 -169.5 -378.5t-467.5 -137.5h-86l-109 -520h-305zM522 774h56q142 0 223.5 69t81.5 185q0 180 -195 180h-74z" /> +<glyph unicode="Q" horiz-adv-x="1495" d="M123 537q0 265 99 487.5t273 341.5t402 119q255 0 395 -144t140 -403q0 -316 -122.5 -555.5t-334.5 -337.5l254 -393h-359l-178 328h-26q-256 0 -399.5 147.5t-143.5 409.5zM434 537q0 -147 66.5 -222t187.5 -75t220.5 87t155.5 246t56 357q0 142 -65 219.5t-183 77.5 q-121 0 -222 -91.5t-158.5 -251.5t-57.5 -347z" /> +<glyph unicode="R" horiz-adv-x="1247" d="M53 0l309 1462h359q237 0 356 -102t119 -299q0 -158 -83 -271.5t-239 -168.5l261 -621h-332l-207 561h-119l-119 -561h-305zM530 813h78q131 0 204 57t73 174q0 82 -47.5 123t-149.5 41h-74z" /> +<glyph unicode="S" horiz-adv-x="1085" d="M41 70v274q193 -108 358 -108q112 0 175 42.5t63 116.5q0 43 -13.5 75.5t-38.5 60.5t-124 102q-138 99 -194 196t-56 209q0 129 62 230.5t176.5 158t263.5 56.5q217 0 397 -99l-109 -233q-156 74 -288 74q-83 0 -136 -45t-53 -119q0 -61 33 -106.5t148 -120.5 q121 -80 181 -176.5t60 -225.5q0 -209 -148 -330.5t-401 -121.5q-221 0 -356 90z" /> +<glyph unicode="T" horiz-adv-x="1087" d="M168 1204l55 258h1010l-55 -258h-353l-254 -1204h-305l254 1204h-352z" /> +<glyph unicode="U" horiz-adv-x="1415" d="M141 401q0 72 15 138l196 923h305l-194 -919q-17 -74 -17 -125q0 -178 189 -178q123 0 195 76.5t104 228.5l194 917h306l-201 -946q-57 -266 -218 -401t-419 -135q-212 0 -333.5 113.5t-121.5 307.5z" /> +<glyph unicode="V" horiz-adv-x="1208" d="M184 1462h295l51 -880q4 -45 4 -133q-2 -103 -6 -150h7q78 221 110 283l432 880h316l-748 -1462h-334z" /> +<glyph unicode="W" horiz-adv-x="1831" d="M184 1462h287l6 -798q0 -52 -4 -173t-10 -174h6q22 64 67 180.5t60 145.5l369 819h270l21 -873q0 -146 -9 -272h6q43 129 131 349l330 796h309l-647 -1462h-346l-22 721l-2 139q0 88 4 158h-4q-46 -146 -115 -299l-324 -719h-338z" /> +<glyph unicode="X" horiz-adv-x="1241" d="M-117 0l576 764l-238 698h320l153 -518l363 518h344l-545 -725l268 -737h-331l-172 543l-396 -543h-342z" /> +<glyph unicode="Y" horiz-adv-x="1155" d="M186 1462h312l129 -592l374 592h342l-618 -903l-119 -559h-303l119 559z" /> +<glyph unicode="Z" horiz-adv-x="1098" d="M-61 0l38 201l777 1005h-543l53 256h936l-41 -202l-782 -1004h596l-53 -256h-981z" /> +<glyph unicode="[" horiz-adv-x="678" d="M-37 -324l381 1786h473l-45 -211h-215l-291 -1364h215l-45 -211h-473z" /> +<glyph unicode="\" horiz-adv-x="862" d="M221 1462h260l224 -1462h-267z" /> +<glyph unicode="]" horiz-adv-x="678" d="M-137 -324l45 211h213l291 1364h-215l45 211h473l-381 -1786h-471z" /> +<glyph unicode="^" horiz-adv-x="1081" d="M20 520l619 950h147l277 -950h-223l-174 633l-402 -633h-244z" /> +<glyph unicode="_" horiz-adv-x="819" d="M-186 -324l30 140h822l-31 -140h-821z" /> +<glyph unicode="`" horiz-adv-x="1135" d="M508 1548v21h311q36 -148 115 -303v-25h-184q-71 69 -138.5 153.5t-103.5 153.5z" /> +<glyph unicode="a" horiz-adv-x="1217" d="M90 385q0 198 72 377.5t189 278t257 98.5q97 0 167.5 -42t109.5 -122h8l57 143h232l-238 -1118h-229l14 145h-4q-134 -165 -319 -165q-147 0 -231.5 106.5t-84.5 298.5zM395 399q0 -88 33.5 -132t95.5 -44q69 0 133 67t103 181.5t39 259.5q0 71 -38.5 117.5t-101.5 46.5 q-68 0 -129.5 -72t-98 -190t-36.5 -234z" /> +<glyph unicode="b" horiz-adv-x="1219" d="M37 0l330 1556h301l-62 -288q-41 -182 -84 -299h8q78 98 142.5 134t140.5 36q146 0 230.5 -108t84.5 -298t-68 -367.5t-187 -281.5t-263 -104q-194 0 -276 163h-8l-58 -143h-231zM420 399q0 -80 37 -128t102 -48q67 0 128 69t98.5 189.5t37.5 237.5q0 176 -131 176 q-68 0 -130 -65t-102 -180.5t-40 -250.5z" /> +<glyph unicode="c" horiz-adv-x="989" d="M90 391q0 212 74.5 385.5t209.5 268t308 94.5q182 0 328 -72l-92 -229q-54 23 -106 40t-118 17q-85 0 -153.5 -64t-107 -175.5t-38.5 -239.5q0 -96 45.5 -144.5t126.5 -48.5q76 0 141 23.5t134 58.5v-246q-152 -79 -336 -79q-201 0 -308.5 107.5t-107.5 303.5z" /> +<glyph unicode="d" horiz-adv-x="1217" d="M90 387q0 196 71.5 374.5t188.5 278t258 99.5q82 0 141.5 -37t112.5 -127h8l2 28q6 110 25 195l76 358h301l-330 -1556h-229l14 145h-4q-71 -87 -148.5 -126t-170.5 -39q-147 0 -231.5 107t-84.5 300zM395 399q0 -176 137 -176q66 0 128.5 68.5t100.5 182.5t38 245 q0 80 -37.5 128t-102.5 48q-68 0 -129.5 -72t-98 -190t-36.5 -234z" /> +<glyph unicode="e" horiz-adv-x="1141" d="M90 412q0 207 82.5 377.5t223.5 260t319 89.5q177 0 276 -81.5t99 -223.5q0 -187 -167 -288.5t-477 -101.5h-51l-2 -21v-20q0 -91 51.5 -143.5t147.5 -52.5q87 0 158 19t172 67v-227q-172 -86 -390 -86q-210 0 -326 113t-116 319zM428 647h45q155 0 241.5 48.5 t86.5 131.5q0 95 -105 95q-88 0 -166 -80t-102 -195z" /> +<glyph unicode="f" horiz-adv-x="764" d="M-219 -225q61 -21 115 -21q61 0 107 40t65 130l204 965h-163l30 145l183 84l18 84q41 190 138.5 277.5t273.5 87.5q131 0 235 -49l-80 -224q-69 31 -133 31q-57 0 -92 -40t-47 -105l-12 -62h219l-49 -229h-220l-215 -1010q-77 -371 -403 -371q-104 0 -174 25v242z" /> +<glyph unicode="g" horiz-adv-x="1108" d="M-115 -209q0 102 68.5 175.5t214.5 121.5q-74 47 -74 133q0 71 44.5 122.5t146.5 98.5q-65 49 -96 112t-31 153q0 199 125.5 315.5t341.5 116.5q83 0 166 -23h395l-35 -166l-174 -41q16 -52 16 -118q0 -195 -121 -308.5t-329 -113.5q-59 0 -99 10q-84 -27 -84 -78 q0 -34 30 -49t89 -23l137 -18q163 -21 237.5 -84.5t74.5 -183.5q0 -211 -156 -323t-446 -112q-208 0 -324.5 75.5t-116.5 207.5zM150 -172q0 -115 194 -115q151 0 228 45t77 127q0 39 -32.5 60t-137.5 35l-114 14q-106 -14 -160.5 -57t-54.5 -109zM442 680q0 -119 103 -119 q75 0 121.5 76.5t46.5 193.5t-99 117q-77 0 -124.5 -76.5t-47.5 -191.5z" /> +<glyph unicode="h" horiz-adv-x="1237" d="M37 0l330 1556h301q-39 -181 -60 -278t-86 -309h8q62 77 138 123.5t176 46.5q138 0 213.5 -83.5t75.5 -238.5q0 -73 -23 -180l-133 -637h-301l137 653q16 68 16 119q0 123 -108 123q-92 0 -167 -114t-118 -318l-98 -463h-301z" /> +<glyph unicode="i" horiz-adv-x="608" d="M37 0l237 1118h301l-237 -1118h-301zM322 1380q0 87 47.5 131.5t134.5 44.5q73 0 111 -31t38 -89q0 -80 -44 -129.5t-136 -49.5q-151 0 -151 123z" /> +<glyph unicode="j" horiz-adv-x="608" d="M-264 -225q61 -21 114 -21q137 0 173 170l253 1194h302l-265 -1239q-77 -371 -403 -371q-104 0 -174 25v242zM324 1380q0 87 47.5 131.5t134.5 44.5q73 0 111 -31t38 -89q0 -80 -44 -129.5t-136 -49.5q-151 0 -151 123z" /> +<glyph unicode="k" horiz-adv-x="1163" d="M37 0l330 1556h301l-148 -694q-8 -41 -29 -117l-28 -102h4l453 475h344l-498 -504l285 -614h-336l-183 420l-120 -72l-74 -348h-301z" /> +<glyph unicode="l" horiz-adv-x="608" d="M37 0l330 1556h301l-330 -1556h-301z" /> +<glyph unicode="m" horiz-adv-x="1853" d="M37 0l237 1118h230l-21 -207h6q146 228 355 228q219 0 262 -228h6q68 110 160.5 169t197.5 59q136 0 207.5 -85t71.5 -237q0 -76 -23 -180l-133 -637h-301l138 653q16 68 16 119q0 123 -98 123q-92 0 -166.5 -112t-118.5 -318l-96 -465h-301l137 653q16 68 16 119 q0 123 -98 123q-92 0 -167 -114t-118 -318l-98 -463h-301z" /> +<glyph unicode="n" horiz-adv-x="1237" d="M37 0l237 1118h230l-21 -207h6q146 228 355 228q138 0 213.5 -83.5t75.5 -238.5q0 -73 -23 -180l-133 -637h-301l137 653q16 68 16 119q0 123 -108 123q-92 0 -167 -114t-118 -318l-98 -463h-301z" /> +<glyph unicode="o" horiz-adv-x="1198" d="M90 410q0 213 71.5 379.5t206.5 258t316 91.5q196 0 310 -118t114 -325q0 -211 -70.5 -374t-203.5 -252.5t-316 -89.5q-195 0 -311.5 117.5t-116.5 312.5zM393 410q0 -185 150 -185q75 0 135 61.5t93.5 171t33.5 238.5q0 197 -143 197q-75 0 -134.5 -61t-97 -179 t-37.5 -243z" /> +<glyph unicode="p" horiz-adv-x="1219" d="M-68 -492l342 1610h230l-17 -170h9q138 191 317 191q146 0 230.5 -107.5t84.5 -300.5q0 -191 -68.5 -367.5t-187.5 -280t-262 -103.5q-83 0 -143 37t-111 126h-8q-12 -159 -43 -295l-72 -340h-301zM420 399q0 -80 37 -128t102 -48q67 0 128 69t98.5 189.5t37.5 237.5 q0 176 -131 176q-68 0 -131.5 -67.5t-102 -180t-38.5 -248.5z" /> +<glyph unicode="q" horiz-adv-x="1217" d="M90 385q0 198 72 377.5t189 278t257 98.5q86 0 152.5 -37.5t124.5 -126.5h8l57 143h232l-342 -1610h-301q47 218 73 337.5t84 304.5h-8q-72 -94 -143 -132t-154 -38q-88 0 -156 47.5t-106.5 138.5t-38.5 219zM395 399q0 -88 36.5 -132t103.5 -44q64 0 127.5 70t100 181 t36.5 245q0 80 -37.5 128t-102.5 48q-68 0 -129.5 -72t-98 -190t-36.5 -234z" /> +<glyph unicode="r" horiz-adv-x="862" d="M37 0l237 1118h230l-21 -207h6q147 228 353 228q59 0 96 -11l-66 -290q-45 16 -100 16q-116 0 -203.5 -91.5t-124.5 -262.5l-106 -500h-301z" /> +<glyph unicode="s" horiz-adv-x="969" d="M23 45v248q157 -90 319 -90q80 0 131 32.5t51 88.5q0 43 -37 77t-131 86q-121 68 -169 135.5t-48 159.5q0 170 110.5 263.5t315.5 93.5q201 0 363 -95l-99 -215q-140 84 -258 84q-57 0 -92 -25.5t-35 -68.5q0 -39 32 -68.5t120 -74.5q123 -63 178 -137t55 -170 q0 -188 -124.5 -288.5t-346.5 -100.5q-107 0 -186.5 15t-148.5 50z" /> +<glyph unicode="t" horiz-adv-x="840" d="M94 889l29 147l196 84l132 236h194l-49 -238h283l-50 -229h-282l-115 -539q-6 -30 -6 -53q0 -74 88 -74q65 0 162 35v-225q-111 -53 -266 -53q-150 0 -220.5 63t-70.5 195q0 50 12 112l115 539h-152z" /> +<glyph unicode="u" horiz-adv-x="1237" d="M111 301q0 93 24 213l127 604h301l-137 -653q-16 -68 -16 -119q0 -123 108 -123q92 0 167 114t118 318l98 463h301l-237 -1118h-230l21 207h-6q-145 -227 -355 -227q-138 0 -211 82.5t-73 238.5z" /> +<glyph unicode="v" horiz-adv-x="1049" d="M102 1118h295l45 -586q7 -133 7 -231h6q55 153 92 223l297 594h323l-604 -1118h-323z" /> +<glyph unicode="w" horiz-adv-x="1614" d="M125 1118h281l4 -495l-4 -167l-7 -171h4q6 20 14 41.5t51 136.5t46 119l231 536h328v-536q0 -142 -10 -297h6l28 80q73 208 95 258l219 495h307l-530 -1118h-330l-6 520q0 155 10 340h-6q-62 -178 -123 -319l-233 -541h-324z" /> +<glyph unicode="x" horiz-adv-x="1087" d="M-100 0l479 573l-225 545h321l115 -334l244 334h354l-467 -561l244 -557h-326l-125 342l-264 -342h-350z" /> +<glyph unicode="y" horiz-adv-x="1063" d="M-141 -233q68 -13 116 -13q84 0 147.5 48t117.5 149l26 49l-164 1118h295l56 -518q14 -122 14 -293h6q20 51 44 119.5t65 153.5l260 538h327l-680 -1278q-177 -332 -483 -332q-90 0 -147 19v240z" /> +<glyph unicode="z" horiz-adv-x="932" d="M-47 0l35 180l575 705h-397l51 233h750l-43 -200l-566 -685h439l-49 -233h-795z" /> +<glyph unicode="{" horiz-adv-x="727" d="M-8 459l45 229q122 0 192.5 41.5t92.5 138.5l61 285q38 170 131 239.5t270 69.5h84l-49 -225q-90 -2 -130.5 -34.5t-55.5 -106.5l-66 -297q-45 -207 -276 -236v-8q85 -26 126.5 -82.5t41.5 -134.5q0 -44 -15 -113l-36 -178q-7 -28 -7 -51q0 -54 33.5 -74t91.5 -20v-226 h-53q-167 0 -253.5 63.5t-86.5 184.5q0 57 14 125l39 184q15 69 15 86q0 140 -209 140z" /> +<glyph unicode="|" d="M455 -465v2015h219v-2015h-219z" /> +<glyph unicode="}" horiz-adv-x="727" d="M-100 -98q93 3 137 35.5t59 105.5l66 297q25 111 95 166t181 69v9q-168 51 -168 217q0 43 15 112l37 179q6 30 6 51q0 54 -36.5 74t-109.5 20l41 225h33q340 0 340 -248q0 -56 -14 -124l-39 -185q-15 -69 -15 -86q0 -139 209 -139l-45 -229q-122 0 -192.5 -42t-91.5 -139 l-62 -284q-37 -170 -130.5 -240t-270.5 -70h-45v226z" /> +<glyph unicode="~" d="M109 551v231q101 109 256 109q64 0 117 -14t139 -50q64 -27 111 -41t95 -14q51 0 112 30.5t122 90.5v-231q-103 -109 -256 -109q-59 0 -109 11.5t-147 51.5q-89 38 -127 47t-80 9q-54 0 -116.5 -33t-116.5 -88z" /> +<glyph unicode="&#xa1;" horiz-adv-x="586" d="M-74 -371l256 977h242l-158 -977h-340zM195 924q0 85 54 139.5t144 54.5q73 0 114.5 -37t41.5 -104q0 -92 -55.5 -145.5t-149.5 -53.5q-68 0 -108.5 38t-40.5 108z" /> +<glyph unicode="&#xa2;" d="M164 584q0 193 62.5 355t178 262.5t267.5 123.5l33 158h188l-35 -158q118 -14 225 -65l-92 -230q-53 23 -105 40t-118 17q-133 0 -216 -143t-83 -336q0 -96 45 -144t127 -48q75 0 140 23.5t134 58.5v-246q-136 -71 -299 -80l-41 -192h-188l49 210q-134 36 -203 136 t-69 258z" /> +<glyph unicode="&#xa3;" d="M-12 0l49 246q196 48 244 264l22 104h-192l45 220h192l49 247q41 197 162 300.5t313 103.5q195 0 369 -86l-113 -232q-141 68 -237 68q-75 0 -123 -39.5t-68 -132.5l-47 -229h299l-45 -220h-299l-18 -84q-42 -195 -209 -270h655l-55 -260h-993z" /> +<glyph unicode="&#xa4;" d="M115 1047l147 147l127 -127q91 53 197 53q105 0 196 -55l127 129l150 -143l-129 -129q53 -89 53 -199q0 -107 -53 -199l125 -125l-146 -145l-127 125q-95 -51 -196 -51q-115 0 -199 51l-125 -123l-145 145l127 125q-54 93 -54 197q0 102 54 197zM397 723 q0 -77 54.5 -132.5t134.5 -55.5q81 0 136.5 55t55.5 133q0 80 -56.5 135t-135.5 55q-78 0 -133.5 -56t-55.5 -134z" /> +<glyph unicode="&#xa5;" d="M88 221l37 178h252l29 138h-252l39 178h196l-192 747h297l114 -590l371 590h311l-506 -747h203l-39 -178h-252l-28 -138h252l-37 -178h-252l-47 -221h-291l47 221h-252z" /> +<glyph unicode="&#xa6;" d="M455 350h219v-815h-219v815zM455 735v815h219v-815h-219z" /> +<glyph unicode="&#xa7;" horiz-adv-x="995" d="M20 55v224q172 -105 345 -105q99 0 144.5 35t45.5 92q0 39 -33 72.5t-127 79.5q-117 57 -181 131t-64 176q0 89 47.5 163t154.5 142q-42 34 -70 84.5t-28 107.5q0 149 117 234.5t313 85.5q172 0 344 -88l-82 -193q-147 84 -282 84q-144 0 -144 -106q0 -43 40.5 -76 t127.5 -72q242 -106 242 -303q0 -188 -193 -303q38 -35 64 -85.5t26 -108.5q0 -161 -126 -253.5t-345 -92.5q-204 0 -336 75zM393 797q0 -54 43.5 -96.5t143.5 -88.5q49 31 75.5 78.5t26.5 95.5q0 109 -176 181q-51 -25 -82 -70.5t-31 -99.5z" /> +<glyph unicode="&#xa8;" horiz-adv-x="1135" d="M397 1382q0 78 42.5 118t119.5 40q133 0 133 -108q0 -73 -39 -116.5t-121 -43.5q-135 0 -135 110zM799 1382q0 78 42 118t120 40q65 0 99 -28t34 -80q0 -73 -39.5 -116.5t-120.5 -43.5q-135 0 -135 110z" /> +<glyph unicode="&#xa9;" horiz-adv-x="1704" d="M125 731q0 200 100 375t275 276t377 101q199 0 373.5 -99t276 -275.5t101.5 -377.5q0 -199 -98.5 -373t-272.5 -276t-380 -102q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM266 731q0 -164 81.5 -305t224 -223t305.5 -82q167 0 308 83t221.5 223.5t80.5 303.5 t-80.5 303.5t-222 223.5t-307.5 83q-164 0 -306.5 -82.5t-223.5 -223.5t-81 -304zM485 721q0 225 117.5 351t325.5 126q142 0 284 -72l-75 -174q-114 58 -205 58q-111 0 -163 -73t-52 -214q0 -134 55.5 -203t159.5 -69q43 0 108.5 15.5t124.5 43.5v-191q-131 -57 -262 -57 q-196 0 -307 122.5t-111 336.5z" /> +<glyph unicode="&#xaa;" horiz-adv-x="772" d="M152 1020q0 117 46 228t123 171t177 60q120 0 180 -103h6l39 90h154l-158 -702h-154l8 92h-2q-80 -104 -202 -104q-103 0 -160 70t-57 198zM356 1014q0 -111 86 -111q45 0 84 41.5t65.5 120t26.5 154.5q0 106 -88 106q-73 0 -123.5 -96t-50.5 -215z" /> +<glyph unicode="&#xab;" horiz-adv-x="1151" d="M72 551v18l401 463l191 -155l-279 -334l135 -350l-246 -103zM559 551v18l402 463l190 -155l-279 -334l136 -350l-246 -103z" /> +<glyph unicode="&#xac;" d="M109 612v219h952v-583h-219v364h-733z" /> +<glyph unicode="&#xad;" horiz-adv-x="659" d="M41 424l53 250h524l-53 -250h-524z" /> +<glyph unicode="&#xae;" horiz-adv-x="1704" d="M125 731q0 200 100 375t275 276t377 101q199 0 373.5 -99t276 -275.5t101.5 -377.5q0 -199 -98.5 -373t-272.5 -276t-380 -102q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM266 731q0 -164 81.5 -305t224 -223t305.5 -82q167 0 308 83t221.5 223.5t80.5 303.5 t-80.5 303.5t-222 223.5t-307.5 83q-164 0 -306.5 -82.5t-223.5 -223.5t-81 -304zM571 293v874h308q173 0 265.5 -67.5t92.5 -200.5q0 -86 -44 -149.5t-130 -96.5l197 -360h-254l-138 297h-67v-297h-230zM801 758h51q72 0 113 31t41 92q0 59 -35.5 88.5t-116.5 29.5h-53 v-241z" /> +<glyph unicode="&#xaf;" horiz-adv-x="1024" d="M-6 1556l45 201h1036l-45 -201h-1036z" /> +<glyph unicode="&#xb0;" horiz-adv-x="877" d="M164 1137q0 93 46.5 173.5t127.5 126.5t172 46q93 0 173.5 -47t126.5 -127t46 -172q0 -93 -46 -173t-126 -125.5t-174 -45.5q-93 0 -173 45t-126.5 125t-46.5 174zM354 1137q0 -63 45.5 -108.5t110.5 -45.5q66 0 111 46t45 108q0 63 -45.5 110t-110.5 47t-110.5 -47.5 t-45.5 -109.5z" /> +<glyph unicode="&#xb1;" d="M109 0v219h952v-219h-952zM109 674v219h366v369h219v-369h367v-219h-367v-365h-219v365h-366z" /> +<glyph unicode="&#xb2;" horiz-adv-x="776" d="M59 586l35 166l273 219q111 91 141 122t44.5 59t14.5 56q0 42 -25.5 62t-60.5 20q-86 0 -188 -82l-100 158q74 57 156 87t192 30q123 0 196.5 -63t73.5 -160q0 -70 -22 -123t-70 -103.5t-189 -152.5l-129 -95h347l-41 -200h-648z" /> +<glyph unicode="&#xb3;" horiz-adv-x="776" d="M92 625v192q125 -72 254 -72q76 0 125 30.5t49 88.5q0 37 -26 62.5t-88 25.5h-127l34 160h90q84 0 132.5 28t48.5 85q0 40 -26 60t-71 20q-86 0 -188 -66l-82 150q142 92 313 92q130 0 206.5 -55.5t76.5 -155.5q0 -87 -51 -145.5t-166 -88.5v-4q154 -33 154 -176 q0 -131 -107 -209t-285 -78q-75 0 -145.5 15.5t-120.5 40.5z" /> +<glyph unicode="&#xb4;" horiz-adv-x="1135" d="M483 1241v25q79 88 222 303h335v-17q-46 -56 -154 -152.5t-194 -158.5h-209z" /> +<glyph unicode="&#xb5;" horiz-adv-x="1249" d="M-68 -492l342 1610h301l-135 -645q-16 -70 -16 -125q0 -60 31.5 -92.5t79.5 -32.5q90 0 162.5 106.5t117.5 319.5l98 469h301l-237 -1118h-229l18 176h-6q-117 -196 -266 -196q-51 0 -89.5 19.5t-58.5 47.5h-6q-8 -66 -21.5 -139t-82.5 -400h-304z" /> +<glyph unicode="&#xb6;" horiz-adv-x="1341" d="M147 1042q0 256 107.5 385t343.5 129h604v-1816h-162v1616h-166v-1616h-161v819q-62 -18 -146 -18q-216 0 -318 125t-102 376z" /> +<glyph unicode="&#xb7;" horiz-adv-x="584" d="M131 695q0 90 53.5 144t150.5 54q68 0 109 -38t41 -107q0 -87 -55 -141t-144 -54q-73 0 -114 37.5t-41 104.5z" /> +<glyph unicode="&#xb8;" horiz-adv-x="420" d="M-207 -301q63 -23 125 -23q102 0 102 82q0 34 -31 56.5t-110 31.5l96 154h185l-39 -72q141 -49 141 -178q0 -116 -83 -179t-234 -63q-86 0 -152 23v168z" /> +<glyph unicode="&#xb9;" horiz-adv-x="776" d="M129 1214l399 248h207l-186 -876h-246l84 397q24 109 55 207q-16 -15 -80 -60l-131 -81z" /> +<glyph unicode="&#xba;" horiz-adv-x="754" d="M162 1038q0 197 104 319t277 122q129 0 197.5 -73.5t68.5 -211.5q0 -128 -48.5 -232.5t-132.5 -157t-196 -52.5q-134 0 -202 75t-68 211zM371 1026q0 -111 80 -111q63 0 105 85.5t42 207.5q0 107 -76 107q-64 0 -107.5 -89.5t-43.5 -199.5z" /> +<glyph unicode="&#xbb;" horiz-adv-x="1151" d="M0 227l279 334l-136 350l246 103l203 -461v-18l-402 -463zM487 227l279 334l-135 350l246 103l202 -461v-18l-401 -463z" /> +<glyph unicode="&#xbc;" horiz-adv-x="1804" d="M177 0l1087 1462h236l-1084 -1462h-239zM97 1214l399 248h207l-186 -876h-246l84 397q24 109 55 207q-16 -15 -80 -60l-131 -81zM844 152l31 174l475 557h260l-121 -563h119l-35 -168h-119l-32 -151h-238l33 151h-373zM1078 320h174l58 231l22 74q-13 -20 -43 -58 t-211 -247z" /> +<glyph unicode="&#xbd;" horiz-adv-x="1804" d="M940 1l35 166l273 219q111 91 141 122t44.5 59t14.5 56q0 42 -25.5 62t-60.5 20q-86 0 -188 -82l-100 158q74 57 156 87t192 30q123 0 196.5 -63t73.5 -160q0 -70 -22 -123t-70 -103.5t-189 -152.5l-129 -95h347l-41 -200h-648zM97 1214l399 248h207l-186 -876h-246 l84 397q24 109 55 207q-16 -15 -80 -60l-131 -81zM177 0l1087 1462h236l-1084 -1462h-239z" /> +<glyph unicode="&#xbe;" horiz-adv-x="1804" d="M310 0l1087 1462h236l-1084 -1462h-239zM905 152l31 174l475 557h260l-121 -563h119l-35 -168h-119l-32 -151h-238l33 151h-373zM1139 320h174l58 231l22 74q-13 -20 -43 -58t-211 -247zM133 625v192q125 -72 254 -72q76 0 125 30.5t49 88.5q0 37 -26 62.5t-88 25.5h-127 l34 160h90q84 0 132.5 28t48.5 85q0 40 -26 60t-71 20q-86 0 -188 -66l-82 150q142 92 313 92q130 0 206.5 -55.5t76.5 -155.5q0 -87 -51 -145.5t-166 -88.5v-4q154 -33 154 -176q0 -131 -107 -209t-285 -78q-75 0 -145.5 15.5t-120.5 40.5z" /> +<glyph unicode="&#xbf;" horiz-adv-x="940" d="M-68 -59q0 82 28.5 148.5t83.5 124t189 146.5q93 62 128 106.5t51 106.5l8 33h258l-14 -78q-19 -105 -76.5 -180t-169.5 -151q-122 -83 -156.5 -126t-34.5 -98q0 -118 133 -118q50 0 106.5 16t201.5 84l92 -221q-221 -125 -445 -125q-177 0 -280 87.5t-103 244.5z M418 924q0 86 54.5 140t143.5 54q73 0 114.5 -37t41.5 -104q0 -92 -55.5 -145.5t-149.5 -53.5q-68 0 -108.5 38t-40.5 108z" /> +<glyph unicode="&#xc0;" horiz-adv-x="1286" d="M-123 0l766 1468h373l147 -1468h-297l-24 348h-473l-172 -348h-320zM494 608h333l-26 350q-10 131 -10 253v36q-44 -120 -109 -254zM539 1886v21h311q36 -148 115 -303v-25h-184q-71 69 -138.5 153.5t-103.5 153.5z" /> +<glyph unicode="&#xc1;" horiz-adv-x="1286" d="M-123 0l766 1468h373l147 -1468h-297l-24 348h-473l-172 -348h-320zM494 608h333l-26 350q-10 131 -10 253v36q-44 -120 -109 -254zM735 1579v25q79 88 222 303h335v-17q-46 -56 -154 -152.5t-194 -158.5h-209z" /> +<glyph unicode="&#xc2;" horiz-adv-x="1286" d="M-123 0l766 1468h373l147 -1468h-297l-24 348h-473l-172 -348h-320zM494 608h333l-26 350q-10 131 -10 253v36q-44 -120 -109 -254zM426 1579v25q63 57 153 147t142 156h338q22 -54 74 -142.5t102 -160.5v-25h-198q-63 53 -162 168q-105 -88 -232 -168h-217z" /> +<glyph unicode="&#xc3;" horiz-adv-x="1286" d="M-123 0l766 1468h373l147 -1468h-297l-24 348h-473l-172 -348h-320zM494 608h333l-26 350q-10 131 -10 253v36q-44 -120 -109 -254zM448 1577q59 309 281 309q49 0 87.5 -16.5t71.5 -36t62 -35.5t60 -16q34 0 58 25.5t46 80.5h172q-66 -309 -287 -309q-49 0 -86.5 16.5 t-69.5 36t-61.5 36t-62.5 16.5q-31 0 -55.5 -28t-38.5 -79h-177z" /> +<glyph unicode="&#xc4;" horiz-adv-x="1286" d="M-123 0l766 1468h373l147 -1468h-297l-24 348h-473l-172 -348h-320zM494 608h333l-26 350q-10 131 -10 253v36q-44 -120 -109 -254zM516 1720q0 78 42.5 118t119.5 40q133 0 133 -108q0 -73 -39 -116.5t-121 -43.5q-135 0 -135 110zM918 1720q0 78 42 118t120 40 q65 0 99 -28t34 -80q0 -73 -39.5 -116.5t-120.5 -43.5q-135 0 -135 110z" /> +<glyph unicode="&#xc5;" horiz-adv-x="1286" d="M-123 0l766 1468h373l147 -1468h-297l-24 348h-473l-172 -348h-320zM494 608h333l-26 350q-10 131 -10 253v36q-44 -120 -109 -254zM585 1565q0 109 68.5 173t179.5 64q110 0 182 -65t72 -170q0 -107 -70 -173.5t-184 -66.5q-110 0 -179 63.5t-69 174.5zM737 1565 q0 -45 24 -71t72 -26q42 0 69.5 26t27.5 71t-27.5 70.5t-69.5 25.5t-69 -25.5t-27 -70.5z" /> +<glyph unicode="&#xc6;" horiz-adv-x="1833" d="M-123 0l922 1462h1104l-54 -254h-512l-67 -321h477l-55 -254h-478l-79 -377h512l-54 -256h-817l74 348h-426l-219 -348h-328zM588 608h317l127 600h-80z" /> +<glyph unicode="&#xc7;" horiz-adv-x="1253" d="M123 553q0 262 104 482.5t278 335t400 114.5q125 0 222 -22.5t208 -82.5l-118 -250q-106 59 -175 78t-137 19q-132 0 -237.5 -81t-169.5 -238.5t-64 -338.5q0 -167 68.5 -248t218.5 -81q146 0 338 77v-260q-199 -77 -400 -77q-254 0 -395 149.5t-141 423.5zM356 -301 q63 -23 125 -23q102 0 102 82q0 34 -31 56.5t-110 31.5l96 154h185l-39 -72q141 -49 141 -178q0 -116 -83 -179t-234 -63q-86 0 -152 23v168z" /> +<glyph unicode="&#xc8;" horiz-adv-x="1110" d="M53 0l309 1462h818l-54 -254h-512l-67 -321h477l-55 -254h-477l-80 -377h512l-54 -256h-817zM480 1886v21h311q36 -148 115 -303v-25h-184q-71 69 -138.5 153.5t-103.5 153.5z" /> +<glyph unicode="&#xc9;" horiz-adv-x="1110" d="M53 0l309 1462h818l-54 -254h-512l-67 -321h477l-55 -254h-477l-80 -377h512l-54 -256h-817zM608 1579v25q79 88 222 303h335v-17q-46 -56 -154 -152.5t-194 -158.5h-209z" /> +<glyph unicode="&#xca;" horiz-adv-x="1110" d="M53 0l309 1462h818l-54 -254h-512l-67 -321h477l-55 -254h-477l-80 -377h512l-54 -256h-817zM368 1579v25q63 57 153 147t142 156h338q22 -54 74 -142.5t102 -160.5v-25h-198q-63 53 -162 168q-105 -88 -232 -168h-217z" /> +<glyph unicode="&#xcb;" horiz-adv-x="1110" d="M53 0l309 1462h818l-54 -254h-512l-67 -321h477l-55 -254h-477l-80 -377h512l-54 -256h-817zM438 1720q0 78 42.5 118t119.5 40q133 0 133 -108q0 -73 -39 -116.5t-121 -43.5q-135 0 -135 110zM840 1720q0 78 42 118t120 40q65 0 99 -28t34 -80q0 -73 -39.5 -116.5 t-120.5 -43.5q-135 0 -135 110z" /> +<glyph unicode="&#xcc;" horiz-adv-x="659" d="M53 0l312 1462h305l-312 -1462h-305zM241 1886v21h311q36 -148 115 -303v-25h-184q-71 69 -138.5 153.5t-103.5 153.5z" /> +<glyph unicode="&#xcd;" horiz-adv-x="659" d="M53 0l312 1462h305l-312 -1462h-305zM414 1579v25q79 88 222 303h335v-17q-46 -56 -154 -152.5t-194 -158.5h-209z" /> +<glyph unicode="&#xce;" horiz-adv-x="659" d="M53 0l312 1462h305l-312 -1462h-305zM128 1579v25q63 57 153 147t142 156h338q22 -54 74 -142.5t102 -160.5v-25h-198q-63 53 -162 168q-105 -88 -232 -168h-217z" /> +<glyph unicode="&#xcf;" horiz-adv-x="659" d="M53 0l312 1462h305l-312 -1462h-305zM222 1720q0 78 42.5 118t119.5 40q133 0 133 -108q0 -73 -39 -116.5t-121 -43.5q-135 0 -135 110zM624 1720q0 78 42 118t120 40q65 0 99 -28t34 -80q0 -73 -39.5 -116.5t-120.5 -43.5q-135 0 -135 110z" /> +<glyph unicode="&#xd0;" horiz-adv-x="1386" d="M37 596l55 254h139l131 612h396q270 0 417.5 -143t147.5 -410q0 -280 -98 -486.5t-283.5 -314.5t-437.5 -108h-451l125 596h-141zM412 256h106q148 0 258 76t172 223.5t62 337.5q0 154 -72.5 234.5t-208.5 80.5h-115l-75 -358h237l-55 -254h-238z" /> +<glyph unicode="&#xd1;" horiz-adv-x="1546" d="M53 0l309 1462h357l340 -1077h4q12 76 39 217t180 860h274l-309 -1462h-342l-356 1106h-6l-4 -32q-32 -216 -66 -386l-145 -688h-275zM563 1577q59 309 281 309q49 0 87.5 -16.5t71.5 -36t62 -35.5t60 -16q34 0 58 25.5t46 80.5h172q-66 -309 -287 -309q-49 0 -86.5 16.5 t-69.5 36t-61.5 36t-62.5 16.5q-31 0 -55.5 -28t-38.5 -79h-177z" /> +<glyph unicode="&#xd2;" horiz-adv-x="1495" d="M123 537q0 265 99 487.5t273 341.5t402 119q255 0 395 -144t140 -403q0 -283 -99 -506.5t-271 -337.5t-396 -114q-256 0 -399.5 147.5t-143.5 409.5zM434 537q0 -147 66.5 -222t187.5 -75t220.5 87t155.5 246t56 357q0 142 -65 219.5t-183 77.5q-121 0 -222 -91.5 t-158.5 -251.5t-57.5 -347zM627 1886v21h311q36 -148 115 -303v-25h-184q-71 69 -138.5 153.5t-103.5 153.5z" /> +<glyph unicode="&#xd3;" horiz-adv-x="1495" d="M123 537q0 265 99 487.5t273 341.5t402 119q255 0 395 -144t140 -403q0 -283 -99 -506.5t-271 -337.5t-396 -114q-256 0 -399.5 147.5t-143.5 409.5zM434 537q0 -147 66.5 -222t187.5 -75t220.5 87t155.5 246t56 357q0 142 -65 219.5t-183 77.5q-121 0 -222 -91.5 t-158.5 -251.5t-57.5 -347zM753 1579v25q79 88 222 303h335v-17q-46 -56 -154 -152.5t-194 -158.5h-209z" /> +<glyph unicode="&#xd4;" horiz-adv-x="1495" d="M123 537q0 265 99 487.5t273 341.5t402 119q255 0 395 -144t140 -403q0 -283 -99 -506.5t-271 -337.5t-396 -114q-256 0 -399.5 147.5t-143.5 409.5zM434 537q0 -147 66.5 -222t187.5 -75t220.5 87t155.5 246t56 357q0 142 -65 219.5t-183 77.5q-121 0 -222 -91.5 t-158.5 -251.5t-57.5 -347zM499 1579v25q63 57 153 147t142 156h338q22 -54 74 -142.5t102 -160.5v-25h-198q-63 53 -162 168q-105 -88 -232 -168h-217z" /> +<glyph unicode="&#xd5;" horiz-adv-x="1495" d="M123 537q0 265 99 487.5t273 341.5t402 119q255 0 395 -144t140 -403q0 -283 -99 -506.5t-271 -337.5t-396 -114q-256 0 -399.5 147.5t-143.5 409.5zM434 537q0 -147 66.5 -222t187.5 -75t220.5 87t155.5 246t56 357q0 142 -65 219.5t-183 77.5q-121 0 -222 -91.5 t-158.5 -251.5t-57.5 -347zM520 1577q59 309 281 309q49 0 87.5 -16.5t71.5 -36t62 -35.5t60 -16q34 0 58 25.5t46 80.5h172q-66 -309 -287 -309q-49 0 -86.5 16.5t-69.5 36t-61.5 36t-62.5 16.5q-31 0 -55.5 -28t-38.5 -79h-177z" /> +<glyph unicode="&#xd6;" horiz-adv-x="1495" d="M123 537q0 265 99 487.5t273 341.5t402 119q255 0 395 -144t140 -403q0 -283 -99 -506.5t-271 -337.5t-396 -114q-256 0 -399.5 147.5t-143.5 409.5zM434 537q0 -147 66.5 -222t187.5 -75t220.5 87t155.5 246t56 357q0 142 -65 219.5t-183 77.5q-121 0 -222 -91.5 t-158.5 -251.5t-57.5 -347zM585 1720q0 78 42.5 118t119.5 40q133 0 133 -108q0 -73 -39 -116.5t-121 -43.5q-135 0 -135 110zM987 1720q0 78 42 118t120 40q65 0 99 -28t34 -80q0 -73 -39.5 -116.5t-120.5 -43.5q-135 0 -135 110z" /> +<glyph unicode="&#xd7;" d="M129 1024l152 154l301 -299l305 299l153 -150l-305 -305l301 -303l-149 -152l-305 301l-301 -299l-150 152l297 301z" /> +<glyph unicode="&#xd8;" horiz-adv-x="1495" d="M100 29l121 151q-98 138 -98 357q0 265 99 487.5t273 341.5t402 119q182 0 305 -76l105 131l151 -117l-117 -145q91 -134 91 -340q0 -283 -99 -506.5t-271 -337.5t-396 -114q-180 0 -304 71l-108 -137zM424 537q0 -32 8 -101l596 754q-69 43 -158 43q-126 0 -229 -91.5 t-160 -252.5t-57 -352zM539 270q59 -37 153 -37q124 0 226 89t158.5 247.5t56.5 360.5l-5 80z" /> +<glyph unicode="&#xd9;" horiz-adv-x="1415" d="M141 401q0 72 15 138l196 923h305l-194 -919q-17 -74 -17 -125q0 -178 189 -178q123 0 195 76.5t104 228.5l194 917h306l-201 -946q-57 -266 -218 -401t-419 -135q-212 0 -333.5 113.5t-121.5 307.5zM576 1886v21h311q36 -148 115 -303v-25h-184q-71 69 -138.5 153.5 t-103.5 153.5z" /> +<glyph unicode="&#xda;" horiz-adv-x="1415" d="M141 401q0 72 15 138l196 923h305l-194 -919q-17 -74 -17 -125q0 -178 189 -178q123 0 195 76.5t104 228.5l194 917h306l-201 -946q-57 -266 -218 -401t-419 -135q-212 0 -333.5 113.5t-121.5 307.5zM757 1579v25q79 88 222 303h335v-17q-46 -56 -154 -152.5t-194 -158.5 h-209z" /> +<glyph unicode="&#xdb;" horiz-adv-x="1415" d="M141 401q0 72 15 138l196 923h305l-194 -919q-17 -74 -17 -125q0 -178 189 -178q123 0 195 76.5t104 228.5l194 917h306l-201 -946q-57 -266 -218 -401t-419 -135q-212 0 -333.5 113.5t-121.5 307.5zM475 1579v25q63 57 153 147t142 156h338q22 -54 74 -142.5t102 -160.5 v-25h-198q-63 53 -162 168q-105 -88 -232 -168h-217z" /> +<glyph unicode="&#xdc;" horiz-adv-x="1415" d="M141 401q0 72 15 138l196 923h305l-194 -919q-17 -74 -17 -125q0 -178 189 -178q123 0 195 76.5t104 228.5l194 917h306l-201 -946q-57 -266 -218 -401t-419 -135q-212 0 -333.5 113.5t-121.5 307.5zM565 1720q0 78 42.5 118t119.5 40q133 0 133 -108q0 -73 -39 -116.5 t-121 -43.5q-135 0 -135 110zM967 1720q0 78 42 118t120 40q65 0 99 -28t34 -80q0 -73 -39.5 -116.5t-120.5 -43.5q-135 0 -135 110z" /> +<glyph unicode="&#xdd;" horiz-adv-x="1155" d="M186 1462h312l129 -592l374 592h342l-618 -903l-119 -559h-303l119 559zM606 1579v25q79 88 222 303h335v-17q-46 -56 -154 -152.5t-194 -158.5h-209z" /> +<glyph unicode="&#xde;" horiz-adv-x="1188" d="M53 0l309 1462h306l-50 -229h35q242 0 366 -106.5t124 -319.5q0 -243 -170.5 -378.5t-466.5 -135.5h-86l-62 -293h-305zM475 547h55q139 0 222.5 66.5t83.5 185.5q0 180 -195 180h-74z" /> +<glyph unicode="&#xdf;" horiz-adv-x="1350" d="M-260 -225q61 -21 115 -21q133 0 170 178l254 1207q47 224 182 326t385 102q208 0 331 -90t123 -240q0 -114 -49 -192t-178 -152q-73 -42 -96 -68.5t-23 -54.5q0 -23 22 -49.5t79 -69.5q107 -83 144.5 -150.5t37.5 -150.5q0 -170 -123.5 -270t-337.5 -100q-187 0 -297 61 v240q128 -78 258 -78q101 0 148 33t47 86q0 40 -26.5 75t-108.5 97q-94 72 -129 130t-35 126q0 84 45 145t162 127q66 37 104.5 76t38.5 96q0 62 -39.5 98.5t-124.5 36.5q-96 0 -156 -51.5t-85 -171.5l-254 -1219q-43 -198 -147 -288.5t-277 -90.5q-90 0 -160 25v242z" /> +<glyph unicode="&#xe0;" horiz-adv-x="1217" d="M90 385q0 198 72 377.5t189 278t257 98.5q97 0 167.5 -42t109.5 -122h8l57 143h232l-238 -1118h-229l14 145h-4q-134 -165 -319 -165q-147 0 -231.5 106.5t-84.5 298.5zM395 399q0 -88 33.5 -132t95.5 -44q69 0 133 67t103 181.5t39 259.5q0 71 -38.5 117.5t-101.5 46.5 q-68 0 -129.5 -72t-98 -190t-36.5 -234zM443 1548v21h311q36 -148 115 -303v-25h-184q-71 69 -138.5 153.5t-103.5 153.5z" /> +<glyph unicode="&#xe1;" horiz-adv-x="1217" d="M90 385q0 198 72 377.5t189 278t257 98.5q97 0 167.5 -42t109.5 -122h8l57 143h232l-238 -1118h-229l14 145h-4q-134 -165 -319 -165q-147 0 -231.5 106.5t-84.5 298.5zM395 399q0 -88 33.5 -132t95.5 -44q69 0 133 67t103 181.5t39 259.5q0 71 -38.5 117.5t-101.5 46.5 q-68 0 -129.5 -72t-98 -190t-36.5 -234zM598 1241v25q79 88 222 303h335v-17q-46 -56 -154 -152.5t-194 -158.5h-209z" /> +<glyph unicode="&#xe2;" horiz-adv-x="1217" d="M90 385q0 198 72 377.5t189 278t257 98.5q97 0 167.5 -42t109.5 -122h8l57 143h232l-238 -1118h-229l14 145h-4q-134 -165 -319 -165q-147 0 -231.5 106.5t-84.5 298.5zM395 399q0 -88 33.5 -132t95.5 -44q69 0 133 67t103 181.5t39 259.5q0 71 -38.5 117.5t-101.5 46.5 q-68 0 -129.5 -72t-98 -190t-36.5 -234zM311 1240v25q63 57 153 147t142 156h338q22 -54 74 -142.5t102 -160.5v-25h-198q-63 53 -162 168q-105 -88 -232 -168h-217z" /> +<glyph unicode="&#xe3;" horiz-adv-x="1217" d="M90 385q0 198 72 377.5t189 278t257 98.5q97 0 167.5 -42t109.5 -122h8l57 143h232l-238 -1118h-229l14 145h-4q-134 -165 -319 -165q-147 0 -231.5 106.5t-84.5 298.5zM395 399q0 -88 33.5 -132t95.5 -44q69 0 133 67t103 181.5t39 259.5q0 71 -38.5 117.5t-101.5 46.5 q-68 0 -129.5 -72t-98 -190t-36.5 -234zM333 1239q59 309 281 309q49 0 87.5 -16.5t71.5 -36t62 -35.5t60 -16q34 0 58 25.5t46 80.5h172q-66 -309 -287 -309q-49 0 -86.5 16.5t-69.5 36t-61.5 36t-62.5 16.5q-31 0 -55.5 -28t-38.5 -79h-177z" /> +<glyph unicode="&#xe4;" horiz-adv-x="1217" d="M90 385q0 198 72 377.5t189 278t257 98.5q97 0 167.5 -42t109.5 -122h8l57 143h232l-238 -1118h-229l14 145h-4q-134 -165 -319 -165q-147 0 -231.5 106.5t-84.5 298.5zM395 399q0 -88 33.5 -132t95.5 -44q69 0 133 67t103 181.5t39 259.5q0 71 -38.5 117.5t-101.5 46.5 q-68 0 -129.5 -72t-98 -190t-36.5 -234zM397 1382q0 78 42.5 118t119.5 40q133 0 133 -108q0 -73 -39 -116.5t-121 -43.5q-135 0 -135 110zM799 1382q0 78 42 118t120 40q65 0 99 -28t34 -80q0 -73 -39.5 -116.5t-120.5 -43.5q-135 0 -135 110z" /> +<glyph unicode="&#xe5;" horiz-adv-x="1217" d="M90 385q0 198 72 377.5t189 278t257 98.5q97 0 167.5 -42t109.5 -122h8l57 143h232l-238 -1118h-229l14 145h-4q-134 -165 -319 -165q-147 0 -231.5 106.5t-84.5 298.5zM395 399q0 -88 33.5 -132t95.5 -44q69 0 133 67t103 181.5t39 259.5q0 71 -38.5 117.5t-101.5 46.5 q-68 0 -129.5 -72t-98 -190t-36.5 -234zM521 1477q0 109 68.5 173t179.5 64q110 0 182 -65t72 -170q0 -107 -70 -173.5t-184 -66.5q-110 0 -179 63.5t-69 174.5zM673 1477q0 -45 24 -71t72 -26q42 0 69.5 26t27.5 71t-27.5 70.5t-69.5 25.5t-69 -25.5t-27 -70.5z" /> +<glyph unicode="&#xe6;" horiz-adv-x="1786" d="M90 385q0 200 68.5 375.5t185 277t258.5 101.5q96 0 160.5 -38.5t114.5 -125.5h6l57 143h188l-18 -90q44 49 120.5 80t168.5 31q157 0 246.5 -83.5t89.5 -221.5q0 -187 -167 -288.5t-476 -101.5h-52l-2 -19v-19q0 -96 55.5 -147.5t159.5 -51.5q66 0 152 23t162 63v-227 q-179 -86 -361 -86q-109 0 -179.5 27t-117.5 87l-16 -94h-188l14 145h-6q-71 -88 -146.5 -126.5t-167.5 -38.5q-146 0 -227.5 109t-81.5 296zM395 399q0 -84 32.5 -130t90.5 -46q72 0 134 68t99 184.5t37 243.5q0 80 -33 128t-102 48q-68 0 -128 -69t-95 -185.5t-35 -241.5z M1073 647h45q155 0 241.5 48.5t86.5 131.5q0 95 -105 95q-88 0 -166 -80t-102 -195z" /> +<glyph unicode="&#xe7;" horiz-adv-x="989" d="M90 391q0 212 74.5 385.5t209.5 268t308 94.5q182 0 328 -72l-92 -229q-54 23 -106 40t-118 17q-85 0 -153.5 -64t-107 -175.5t-38.5 -239.5q0 -96 45.5 -144.5t126.5 -48.5q76 0 141 23.5t134 58.5v-246q-152 -79 -336 -79q-201 0 -308.5 107.5t-107.5 303.5zM184 -301 q63 -23 125 -23q102 0 102 82q0 34 -31 56.5t-110 31.5l96 154h185l-39 -72q141 -49 141 -178q0 -116 -83 -179t-234 -63q-86 0 -152 23v168z" /> +<glyph unicode="&#xe8;" horiz-adv-x="1141" d="M90 412q0 207 82.5 377.5t223.5 260t319 89.5q177 0 276 -81.5t99 -223.5q0 -187 -167 -288.5t-477 -101.5h-51l-2 -21v-20q0 -91 51.5 -143.5t147.5 -52.5q87 0 158 19t172 67v-227q-172 -86 -390 -86q-210 0 -326 113t-116 319zM428 647h45q155 0 241.5 48.5 t86.5 131.5q0 95 -105 95q-88 0 -166 -80t-102 -195zM423 1548v21h311q36 -148 115 -303v-25h-184q-71 69 -138.5 153.5t-103.5 153.5z" /> +<glyph unicode="&#xe9;" horiz-adv-x="1141" d="M90 412q0 207 82.5 377.5t223.5 260t319 89.5q177 0 276 -81.5t99 -223.5q0 -187 -167 -288.5t-477 -101.5h-51l-2 -21v-20q0 -91 51.5 -143.5t147.5 -52.5q87 0 158 19t172 67v-227q-172 -86 -390 -86q-210 0 -326 113t-116 319zM428 647h45q155 0 241.5 48.5 t86.5 131.5q0 95 -105 95q-88 0 -166 -80t-102 -195zM528 1241v25q79 88 222 303h335v-17q-46 -56 -154 -152.5t-194 -158.5h-209z" /> +<glyph unicode="&#xea;" horiz-adv-x="1141" d="M90 412q0 207 82.5 377.5t223.5 260t319 89.5q177 0 276 -81.5t99 -223.5q0 -187 -167 -288.5t-477 -101.5h-51l-2 -21v-20q0 -91 51.5 -143.5t147.5 -52.5q87 0 158 19t172 67v-227q-172 -86 -390 -86q-210 0 -326 113t-116 319zM428 647h45q155 0 241.5 48.5 t86.5 131.5q0 95 -105 95q-88 0 -166 -80t-102 -195zM292 1241v25q63 57 153 147t142 156h338q22 -54 74 -142.5t102 -160.5v-25h-198q-63 53 -162 168q-105 -88 -232 -168h-217z" /> +<glyph unicode="&#xeb;" horiz-adv-x="1141" d="M90 412q0 207 82.5 377.5t223.5 260t319 89.5q177 0 276 -81.5t99 -223.5q0 -187 -167 -288.5t-477 -101.5h-51l-2 -21v-20q0 -91 51.5 -143.5t147.5 -52.5q87 0 158 19t172 67v-227q-172 -86 -390 -86q-210 0 -326 113t-116 319zM428 647h45q155 0 241.5 48.5 t86.5 131.5q0 95 -105 95q-88 0 -166 -80t-102 -195zM365 1382q0 78 42.5 118t119.5 40q133 0 133 -108q0 -73 -39 -116.5t-121 -43.5q-135 0 -135 110zM767 1382q0 78 42 118t120 40q65 0 99 -28t34 -80q0 -73 -39.5 -116.5t-120.5 -43.5q-135 0 -135 110z" /> +<glyph unicode="&#xec;" horiz-adv-x="608" d="M37 0l237 1118h301l-237 -1118h-301zM153 1548v21h311q36 -148 115 -303v-25h-184q-71 69 -138.5 153.5t-103.5 153.5z" /> +<glyph unicode="&#xed;" horiz-adv-x="608" d="M37 0l237 1118h301l-237 -1118h-301zM291 1241v25q79 88 222 303h335v-17q-46 -56 -154 -152.5t-194 -158.5h-209z" /> +<glyph unicode="&#xee;" horiz-adv-x="608" d="M37 0l237 1118h301l-237 -1118h-301zM36 1241v25q63 57 153 147t142 156h338q22 -54 74 -142.5t102 -160.5v-25h-198q-63 53 -162 168q-105 -88 -232 -168h-217z" /> +<glyph unicode="&#xef;" horiz-adv-x="608" d="M37 0l237 1118h301l-237 -1118h-301zM126 1382q0 78 42.5 118t119.5 40q133 0 133 -108q0 -73 -39 -116.5t-121 -43.5q-135 0 -135 110zM528 1382q0 78 42 118t120 40q65 0 99 -28t34 -80q0 -73 -39.5 -116.5t-120.5 -43.5q-135 0 -135 110z" /> +<glyph unicode="&#xf0;" horiz-adv-x="1182" d="M72 406q0 165 64.5 301t180.5 212t265 76q83 0 151.5 -31t114.5 -94h6q-20 213 -117 310l-231 -131l-88 147l200 113q-34 34 -124 80l118 186q134 -61 232 -139l237 131l76 -152l-192 -106q81 -107 113 -235t32 -279q0 -249 -69.5 -432.5t-203.5 -283t-323 -99.5 q-216 0 -329 110t-113 316zM375 377q0 -81 39 -126.5t114 -45.5q66 0 122.5 55.5t89 148.5t32.5 193q0 77 -38.5 122.5t-108.5 45.5q-73 0 -130 -53t-88.5 -143t-31.5 -197z" /> +<glyph unicode="&#xf1;" horiz-adv-x="1237" d="M37 0l237 1118h230l-21 -207h6q146 228 355 228q138 0 213.5 -83.5t75.5 -238.5q0 -73 -23 -180l-133 -637h-301l137 653q16 68 16 119q0 123 -108 123q-92 0 -167 -114t-118 -318l-98 -463h-301zM358 1239q59 309 281 309q49 0 87.5 -16.5t71.5 -36t62 -35.5t60 -16 q34 0 58 25.5t46 80.5h172q-66 -309 -287 -309q-49 0 -86.5 16.5t-69.5 36t-61.5 36t-62.5 16.5q-31 0 -55.5 -28t-38.5 -79h-177z" /> +<glyph unicode="&#xf2;" horiz-adv-x="1198" d="M90 410q0 213 71.5 379.5t206.5 258t316 91.5q196 0 310 -118t114 -325q0 -211 -70.5 -374t-203.5 -252.5t-316 -89.5q-195 0 -311.5 117.5t-116.5 312.5zM393 410q0 -185 150 -185q75 0 135 61.5t93.5 171t33.5 238.5q0 197 -143 197q-75 0 -134.5 -61t-97 -179 t-37.5 -243zM419 1548v21h311q36 -148 115 -303v-25h-184q-71 69 -138.5 153.5t-103.5 153.5z" /> +<glyph unicode="&#xf3;" horiz-adv-x="1198" d="M90 410q0 213 71.5 379.5t206.5 258t316 91.5q196 0 310 -118t114 -325q0 -211 -70.5 -374t-203.5 -252.5t-316 -89.5q-195 0 -311.5 117.5t-116.5 312.5zM393 410q0 -185 150 -185q75 0 135 61.5t93.5 171t33.5 238.5q0 197 -143 197q-75 0 -134.5 -61t-97 -179 t-37.5 -243zM571 1241v25q79 88 222 303h335v-17q-46 -56 -154 -152.5t-194 -158.5h-209z" /> +<glyph unicode="&#xf4;" horiz-adv-x="1198" d="M90 410q0 213 71.5 379.5t206.5 258t316 91.5q196 0 310 -118t114 -325q0 -211 -70.5 -374t-203.5 -252.5t-316 -89.5q-195 0 -311.5 117.5t-116.5 312.5zM393 410q0 -185 150 -185q75 0 135 61.5t93.5 171t33.5 238.5q0 197 -143 197q-75 0 -134.5 -61t-97 -179 t-37.5 -243zM300 1241v25q63 57 153 147t142 156h338q22 -54 74 -142.5t102 -160.5v-25h-198q-63 53 -162 168q-105 -88 -232 -168h-217z" /> +<glyph unicode="&#xf5;" horiz-adv-x="1198" d="M90 410q0 213 71.5 379.5t206.5 258t316 91.5q196 0 310 -118t114 -325q0 -211 -70.5 -374t-203.5 -252.5t-316 -89.5q-195 0 -311.5 117.5t-116.5 312.5zM393 410q0 -185 150 -185q75 0 135 61.5t93.5 171t33.5 238.5q0 197 -143 197q-75 0 -134.5 -61t-97 -179 t-37.5 -243zM314 1239q59 309 281 309q49 0 87.5 -16.5t71.5 -36t62 -35.5t60 -16q34 0 58 25.5t46 80.5h172q-66 -309 -287 -309q-49 0 -86.5 16.5t-69.5 36t-61.5 36t-62.5 16.5q-31 0 -55.5 -28t-38.5 -79h-177z" /> +<glyph unicode="&#xf6;" horiz-adv-x="1198" d="M90 410q0 213 71.5 379.5t206.5 258t316 91.5q196 0 310 -118t114 -325q0 -211 -70.5 -374t-203.5 -252.5t-316 -89.5q-195 0 -311.5 117.5t-116.5 312.5zM393 410q0 -185 150 -185q75 0 135 61.5t93.5 171t33.5 238.5q0 197 -143 197q-75 0 -134.5 -61t-97 -179 t-37.5 -243zM386 1382q0 78 42.5 118t119.5 40q133 0 133 -108q0 -73 -39 -116.5t-121 -43.5q-135 0 -135 110zM788 1382q0 78 42 118t120 40q65 0 99 -28t34 -80q0 -73 -39.5 -116.5t-120.5 -43.5q-135 0 -135 110z" /> +<glyph unicode="&#xf7;" d="M109 612v219h952v-219h-952zM444 373q0 76 37 113.5t103 37.5t102.5 -39t36.5 -112q0 -70 -37 -111t-102 -41t-102.5 39t-37.5 113zM444 1071q0 75 37 113.5t103 38.5q67 0 103 -40.5t36 -111.5q0 -70 -37 -110.5t-102 -40.5t-102.5 39t-37.5 112z" /> +<glyph unicode="&#xf8;" horiz-adv-x="1198" d="M43 6l119 148q-72 107 -72 256q0 213 71.5 379.5t206.5 258t316 91.5q131 0 227 -56l70 88l145 -110l-84 -105q66 -107 66 -260q0 -211 -70.5 -374t-203.5 -252.5t-316 -89.5q-123 0 -225 53l-109 -135zM385 426l365 453q-35 24 -88 24q-81 0 -144.5 -62.5t-98 -169.5 t-34.5 -233v-12zM457 238q11 -8 35.5 -15.5t50.5 -7.5q114 0 193 133t79 318v16z" /> +<glyph unicode="&#xf9;" horiz-adv-x="1237" d="M111 301q0 93 24 213l127 604h301l-137 -653q-16 -68 -16 -119q0 -123 108 -123q92 0 167 114t118 318l98 463h301l-237 -1118h-230l21 207h-6q-145 -227 -355 -227q-138 0 -211 82.5t-73 238.5zM419 1548v21h311q36 -148 115 -303v-25h-184q-71 69 -138.5 153.5 t-103.5 153.5z" /> +<glyph unicode="&#xfa;" horiz-adv-x="1237" d="M111 301q0 93 24 213l127 604h301l-137 -653q-16 -68 -16 -119q0 -123 108 -123q92 0 167 114t118 318l98 463h301l-237 -1118h-230l21 207h-6q-145 -227 -355 -227q-138 0 -211 82.5t-73 238.5zM610 1241v25q79 88 222 303h335v-17q-46 -56 -154 -152.5t-194 -158.5 h-209z" /> +<glyph unicode="&#xfb;" horiz-adv-x="1237" d="M111 301q0 93 24 213l127 604h301l-137 -653q-16 -68 -16 -119q0 -123 108 -123q92 0 167 114t118 318l98 463h301l-237 -1118h-230l21 207h-6q-145 -227 -355 -227q-138 0 -211 82.5t-73 238.5zM334 1241v25q63 57 153 147t142 156h338q22 -54 74 -142.5t102 -160.5v-25 h-198q-63 53 -162 168q-105 -88 -232 -168h-217z" /> +<glyph unicode="&#xfc;" horiz-adv-x="1237" d="M111 301q0 93 24 213l127 604h301l-137 -653q-16 -68 -16 -119q0 -123 108 -123q92 0 167 114t118 318l98 463h301l-237 -1118h-230l21 207h-6q-145 -227 -355 -227q-138 0 -211 82.5t-73 238.5zM411 1382q0 78 42.5 118t119.5 40q133 0 133 -108q0 -73 -39 -116.5 t-121 -43.5q-135 0 -135 110zM813 1382q0 78 42 118t120 40q65 0 99 -28t34 -80q0 -73 -39.5 -116.5t-120.5 -43.5q-135 0 -135 110z" /> +<glyph unicode="&#xfd;" horiz-adv-x="1063" d="M-141 -233q68 -13 116 -13q84 0 147.5 48t117.5 149l26 49l-164 1118h295l56 -518q14 -122 14 -293h6q20 51 44 119.5t65 153.5l260 538h327l-680 -1278q-177 -332 -483 -332q-90 0 -147 19v240zM497 1241v25q79 88 222 303h335v-17q-46 -56 -154 -152.5t-194 -158.5 h-209z" /> +<glyph unicode="&#xfe;" horiz-adv-x="1219" d="M-68 -492l435 2048h301l-66 -307q-29 -131 -80 -280h8q131 170 283 170q150 0 232.5 -106.5t82.5 -301.5q0 -199 -69 -381t-182 -276t-250 -94q-178 0 -271 163h-8q-12 -159 -43 -295l-72 -340h-301zM420 399q0 -80 33.5 -128t105.5 -48q69 0 129 65t97.5 183.5 t37.5 247.5q0 88 -37.5 132t-103.5 44q-71 0 -130 -65t-95.5 -184.5t-36.5 -246.5z" /> +<glyph unicode="&#xff;" horiz-adv-x="1063" d="M-141 -233q68 -13 116 -13q84 0 147.5 48t117.5 149l26 49l-164 1118h295l56 -518q14 -122 14 -293h6q20 51 44 119.5t65 153.5l260 538h327l-680 -1278q-177 -332 -483 -332q-90 0 -147 19v240zM310 1382q0 78 42.5 118t119.5 40q133 0 133 -108q0 -73 -39 -116.5 t-121 -43.5q-135 0 -135 110zM712 1382q0 78 42 118t120 40q65 0 99 -28t34 -80q0 -73 -39.5 -116.5t-120.5 -43.5q-135 0 -135 110z" /> +<glyph unicode="&#x131;" horiz-adv-x="608" d="M37 0l237 1118h301l-237 -1118h-301z" /> +<glyph unicode="&#x152;" horiz-adv-x="1845" d="M123 537q0 265 99 487.5t273 341.5t402 119q140 0 209 -23h809l-53 -254h-512l-68 -321h477l-55 -254h-477l-80 -377h512l-53 -256h-760q-93 -20 -180 -20q-256 0 -399.5 147.5t-143.5 409.5zM434 537q0 -147 66.5 -222t187.5 -75q88 0 158 32l194 916q-62 39 -168 39 q-121 0 -222 -91.5t-158.5 -251.5t-57.5 -347z" /> +<glyph unicode="&#x153;" horiz-adv-x="1806" d="M90 414q0 216 69 380.5t200 254.5t309 90q209 0 313 -160q154 160 399 160q177 0 276 -81.5t99 -223.5q0 -187 -167 -288.5t-476 -101.5h-51l-2 -21v-20q0 -91 51 -143.5t147 -52.5q87 0 158 19t172 67v-227q-93 -46 -185.5 -66t-203.5 -20q-116 0 -208 38.5t-138 106.5 q-63 -68 -147 -106.5t-207 -38.5q-187 0 -297.5 117t-110.5 317zM393 414q0 -91 36.5 -140t109.5 -49q109 0 179 134.5t70 336.5q0 96 -37 146.5t-106 50.5q-71 0 -127 -60.5t-90.5 -176.5t-34.5 -242zM1094 647h45q155 0 241 48.5t86 131.5q0 95 -104 95 q-88 0 -165.5 -78.5t-102.5 -196.5z" /> +<glyph unicode="&#x178;" horiz-adv-x="1155" d="M186 1462h312l129 -592l374 592h342l-618 -903l-119 -559h-303l119 559zM432 1720q0 78 42.5 118t119.5 40q133 0 133 -108q0 -73 -39 -116.5t-121 -43.5q-135 0 -135 110zM834 1720q0 78 42 118t120 40q65 0 99 -28t34 -80q0 -73 -39.5 -116.5t-120.5 -43.5 q-135 0 -135 110z" /> +<glyph unicode="&#x2c6;" horiz-adv-x="1135" d="M311 1241v25q63 57 153 147t142 156h338q22 -54 74 -142.5t102 -160.5v-25h-198q-63 53 -162 168q-105 -88 -232 -168h-217z" /> +<glyph unicode="&#x2da;" horiz-adv-x="1182" d="M532 1477q0 109 68.5 173t179.5 64q110 0 182 -65t72 -170q0 -107 -70 -173.5t-184 -66.5q-110 0 -179 63.5t-69 174.5zM684 1477q0 -45 24 -71t72 -26q42 0 69.5 26t27.5 71t-27.5 70.5t-69.5 25.5t-69 -25.5t-27 -70.5z" /> +<glyph unicode="&#x2dc;" horiz-adv-x="1135" d="M315 1239q59 309 281 309q49 0 87.5 -16.5t71.5 -36t62 -35.5t60 -16q34 0 58 25.5t46 80.5h172q-66 -309 -287 -309q-49 0 -86.5 16.5t-69.5 36t-61.5 36t-62.5 16.5q-31 0 -55.5 -28t-38.5 -79h-177z" /> +<glyph unicode="&#x2000;" horiz-adv-x="953" /> +<glyph unicode="&#x2001;" horiz-adv-x="1907" /> +<glyph unicode="&#x2002;" horiz-adv-x="953" /> +<glyph unicode="&#x2003;" horiz-adv-x="1907" /> +<glyph unicode="&#x2004;" horiz-adv-x="635" /> +<glyph unicode="&#x2005;" horiz-adv-x="476" /> +<glyph unicode="&#x2006;" horiz-adv-x="317" /> +<glyph unicode="&#x2007;" horiz-adv-x="317" /> +<glyph unicode="&#x2008;" horiz-adv-x="238" /> +<glyph unicode="&#x2009;" horiz-adv-x="381" /> +<glyph unicode="&#x200a;" horiz-adv-x="105" /> +<glyph unicode="&#x2010;" horiz-adv-x="659" d="M41 424l53 250h524l-53 -250h-524z" /> +<glyph unicode="&#x2011;" horiz-adv-x="659" d="M41 424l53 250h524l-53 -250h-524z" /> +<glyph unicode="&#x2012;" horiz-adv-x="659" d="M41 424l53 250h524l-53 -250h-524z" /> +<glyph unicode="&#x2013;" horiz-adv-x="983" d="M41 436l49 230h852l-49 -230h-852z" /> +<glyph unicode="&#x2014;" horiz-adv-x="1966" d="M41 436l49 230h1835l-49 -230h-1835z" /> +<glyph unicode="&#x2018;" horiz-adv-x="440" d="M115 983q103 227 262 479h225q-91 -213 -194 -501h-285z" /> +<glyph unicode="&#x2019;" horiz-adv-x="440" d="M106 961q89 206 195 501h285l8 -22q-103 -227 -262 -479h-226z" /> +<glyph unicode="&#x201a;" horiz-adv-x="569" d="M-102 -264q88 207 194 502h285l8 -23q-103 -227 -262 -479h-225z" /> +<glyph unicode="&#x201c;" horiz-adv-x="887" d="M115 983q103 227 262 479h225q-91 -213 -194 -501h-285zM561 983q103 227 262 479h226q-97 -227 -195 -501h-285z" /> +<glyph unicode="&#x201d;" horiz-adv-x="887" d="M106 961q89 206 195 501h285l8 -22q-103 -227 -262 -479h-226zM553 961q23 53 46.5 111t148.5 390h284l8 -22q-103 -227 -262 -479h-225z" /> +<glyph unicode="&#x201e;" horiz-adv-x="1018" d="M-102 -264q88 207 194 502h285l8 -23q-103 -227 -262 -479h-225zM346 -264q24 57 49 118.5t146 383.5h284l9 -23q-100 -221 -263 -479h-225z" /> +<glyph unicode="&#x2022;" horiz-adv-x="739" d="M104 686q0 106 42.5 194t120 136.5t182.5 48.5q120 0 182.5 -67t62.5 -191q0 -177 -91.5 -277t-248.5 -100q-117 0 -183.5 67t-66.5 189z" /> +<glyph unicode="&#x2026;" horiz-adv-x="1706" d="M25 115q0 90 53.5 144t150.5 54q68 0 109 -38t41 -107q0 -87 -55 -141t-144 -54q-73 0 -114 37.5t-41 104.5zM586 115q0 90 53.5 144t150.5 54q68 0 109 -38t41 -107q0 -87 -55 -141t-144 -54q-73 0 -114 37.5t-41 104.5zM1147 115q0 90 53.5 144t150.5 54q68 0 109 -38 t41 -107q0 -87 -55 -141t-144 -54q-73 0 -114 37.5t-41 104.5z" /> +<glyph unicode="&#x202f;" horiz-adv-x="381" /> +<glyph unicode="&#x2039;" horiz-adv-x="664" d="M72 551v18l401 463l191 -155l-279 -334l135 -350l-246 -103z" /> +<glyph unicode="&#x203a;" horiz-adv-x="664" d="M0 227l279 334l-136 350l246 103l203 -461v-18l-402 -463z" /> +<glyph unicode="&#x2044;" horiz-adv-x="256" d="M-532 0l1087 1462h236l-1084 -1462h-239z" /> +<glyph unicode="&#x205f;" horiz-adv-x="476" /> +<glyph unicode="&#x2074;" horiz-adv-x="776" d="M47 737l31 174l475 557h260l-121 -563h119l-35 -168h-119l-32 -151h-238l33 151h-373zM281 905h174l58 231l22 74q-13 -20 -43 -58t-211 -247z" /> +<glyph unicode="&#x20ac;" d="M41 481l37 178h127q9 67 22 115h-125l39 176h135q87 252 250.5 393.5t374.5 141.5q100 0 179 -23t165 -80l-125 -223q-87 49 -131 63.5t-90 14.5q-97 0 -176 -74.5t-135 -212.5h348l-39 -176h-360q-11 -34 -25 -115h299l-37 -178h-280q0 -120 44.5 -181.5t147.5 -61.5 q133 0 283 63v-258q-126 -63 -330 -63q-446 0 -446 501h-152z" /> +<glyph unicode="&#x2122;" horiz-adv-x="1534" d="M106 1313v149h564v-149h-199v-572h-168v572h-197zM715 741v721h248l159 -510l170 510h240v-721h-168v408l4 121h-6l-174 -529h-141l-166 529h-7l5 -111v-418h-164z" /> +<glyph unicode="&#xe000;" horiz-adv-x="1120" d="M0 1120h1120v-1120h-1120v1120z" /> +<glyph unicode="&#xfb01;" horiz-adv-x="1352" d="M-219 -225q61 -21 115 -21q61 0 107 40t65 130l204 965h-163l30 145l183 84l18 84q41 190 138.5 277.5t273.5 87.5q131 0 235 -49l-80 -224q-69 31 -133 31q-57 0 -92 -40t-47 -105l-12 -62h219l-49 -229h-220l-215 -1010q-77 -371 -403 -371q-104 0 -174 25v242zM780 0 l237 1118h301l-237 -1118h-301zM1065 1380q0 87 47.5 131.5t134.5 44.5q73 0 111 -31t38 -89q0 -80 -44 -129.5t-136 -49.5q-151 0 -151 123z" /> +<glyph unicode="&#xfb02;" horiz-adv-x="1352" d="M-219 -225q61 -21 115 -21q61 0 107 40t65 130l204 965h-163l30 145l183 84l18 84q41 190 138.5 277.5t273.5 87.5q131 0 235 -49l-80 -224q-69 31 -133 31q-57 0 -92 -40t-47 -105l-12 -62h219l-49 -229h-220l-215 -1010q-77 -371 -403 -371q-104 0 -174 25v242zM780 0 l330 1556h301l-330 -1556h-301z" /> +<glyph unicode="&#xfb03;" horiz-adv-x="2048" d="M-219 -225q61 -21 115 -21q61 0 107 40t65 130l204 965h-163l30 145l183 84l18 84q41 190 138.5 277.5t273.5 87.5q131 0 235 -49l-80 -224q-69 31 -133 31q-57 0 -92 -40t-47 -105l-12 -62h395l18 84q41 190 138.5 277.5t273.5 87.5q131 0 235 -49l-79 -224 q-69 31 -134 31q-57 0 -91.5 -40t-47.5 -105l-12 -62h219l-49 -229h-219l-215 -1010q-77 -371 -404 -371q-104 0 -174 25v242q61 -21 115 -21q136 0 172 170l205 965h-396l-215 -1010q-77 -371 -403 -371q-104 0 -174 25v242zM1477 0l237 1118h301l-237 -1118h-301z M1761 1380q0 87 48 131.5t135 44.5q73 0 111 -31t38 -89q0 -80 -44 -129.5t-136 -49.5q-152 0 -152 123z" /> +<glyph unicode="&#xfb04;" horiz-adv-x="2048" d="M-219 -225q61 -21 115 -21q61 0 107 40t65 130l204 965h-163l30 145l183 84l18 84q41 190 138.5 277.5t273.5 87.5q131 0 235 -49l-80 -224q-69 31 -133 31q-57 0 -92 -40t-47 -105l-12 -62h395l18 84q41 190 138.5 277.5t273.5 87.5q131 0 235 -49l-79 -224 q-69 31 -134 31q-57 0 -91.5 -40t-47.5 -105l-12 -62h219l-49 -229h-219l-215 -1010q-77 -371 -404 -371q-104 0 -174 25v242q61 -21 115 -21q136 0 172 170l205 965h-396l-215 -1010q-77 -371 -403 -371q-104 0 -174 25v242zM1477 0l329 1556h301l-329 -1556h-301z" /> +</font> +</defs></svg> +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-BoldItalic-webfont.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.svg b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.svg @@ -0,0 +1,251 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata> +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 2011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom +</metadata> +<defs> +<font id="OpenSansExtrabold" horiz-adv-x="1200" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="&#x09;" horiz-adv-x="532" /> +<glyph unicode="&#xa0;" horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="594" d="M82 1462h432l-51 -946h-330zM86 166q0 91 54 141.5t157 50.5q102 0 154.5 -50.5t52.5 -141.5q0 -90 -54.5 -140.5t-152.5 -50.5q-99 0 -155 50.5t-56 140.5z" /> +<glyph unicode="&#x22;" horiz-adv-x="1073" d="M121 1462h356l-41 -528h-274zM596 1462h356l-41 -528h-274z" /> +<glyph unicode="#" horiz-adv-x="1356" d="M37 391v254h274l31 168h-238v260h287l72 389h268l-74 -389h166l72 389h268l-73 -389h229v-260h-277l-30 -168h243v-254h-290l-74 -391h-268l73 391h-168l-71 -391h-267l72 391h-225zM578 645h165l31 168h-166z" /> +<glyph unicode="$" d="M80 1044q0 165 106 258t318 115v137h207v-135q199 -11 401 -98l-119 -285q-209 94 -377 94q-80 0 -112.5 -19.5t-32.5 -57.5q0 -33 23.5 -54.5t81.5 -48t161 -61.5q209 -74 300 -168.5t91 -243.5q0 -168 -106.5 -273t-310.5 -130v-193h-207v187q-219 10 -422 98v332 q116 -59 252 -98.5t239 -39.5q85 0 124.5 20.5t39.5 68.5q0 33 -28.5 56t-95 52t-179.5 70q-127 47 -205 105.5t-113.5 131t-35.5 180.5zM613 1462z" /> +<glyph unicode="%" horiz-adv-x="1942" d="M37 1026q0 220 98 338.5t275 118.5q175 0 278 -123t103 -334q0 -220 -99 -340.5t-282 -120.5q-172 0 -272.5 124.5t-100.5 336.5zM338 1022q0 -115 19 -166t57 -51t56.5 50t18.5 167q0 115 -18.5 166t-56.5 51q-39 0 -57.5 -52t-18.5 -165zM412 0l811 1462h297 l-811 -1462h-297zM1149 444q0 220 98 338.5t275 118.5q175 0 278 -123t103 -334q0 -219 -99.5 -339.5t-281.5 -120.5q-172 0 -272.5 124.5t-100.5 335.5zM1450 440q0 -115 19 -166t57 -51q43 0 59.5 58.5t16.5 158.5t-16.5 158.5t-59.5 58.5q-39 0 -57.5 -52t-18.5 -165z " /> +<glyph unicode="&#x26;" horiz-adv-x="1636" d="M72 406q0 262 272 401q-62 70 -96.5 148.5t-34.5 177.5q0 160 123.5 254t339.5 94q211 0 328.5 -93.5t117.5 -254.5q0 -111 -63.5 -205.5t-200.5 -177.5l199 -189q75 115 104 260h406q-30 -138 -94.5 -276.5t-145.5 -237.5l320 -307h-506l-99 102q-90 -57 -147.5 -78.5 t-129 -32.5t-163.5 -11q-158 0 -279.5 54t-186 151t-64.5 221zM475 434q0 -63 45 -103t119 -40q57 0 100 15t66 34l-248 252q-82 -61 -82 -158zM565 1120q0 -75 88 -155q57 32 87 76.5t30 91.5q0 49 -28.5 70.5t-71.5 21.5q-42 0 -73.5 -25t-31.5 -80z" /> +<glyph unicode="'" horiz-adv-x="598" d="M121 1462h356l-41 -528h-274z" /> +<glyph unicode="(" horiz-adv-x="735" d="M74 582q0 290 71 523t209 398h326q-126 -175 -194 -412t-68 -507q0 -261 66 -495.5t194 -412.5h-324q-137 158 -208.5 388t-71.5 518zM493 1485z" /> +<glyph unicode=")" horiz-adv-x="735" d="M55 1503h326q139 -166 210 -402t71 -519t-71.5 -514.5t-209.5 -391.5h-324q126 172 193 408.5t67 499.5q0 265 -66 501.5t-196 417.5zM247 1485z" /> +<glyph unicode="*" horiz-adv-x="1100" d="M45 1014l45 291l348 -101l-39 352h303l-38 -352l356 101l37 -295l-314 -21l207 -278l-260 -138l-143 283l-123 -281l-272 136l206 278z" /> +<glyph unicode="+" horiz-adv-x="1159" d="M72 588v268h372v367h269v-367h372v-268h-372v-361h-269v361h-372z" /> +<glyph unicode="," horiz-adv-x="633" d="M57 -285q29 138 58.5 309.5t40.5 274.5h342l14 -23q-97 -381 -176 -561h-279z" /> +<glyph unicode="-" horiz-adv-x="651" d="M43 393v312h565v-312h-565z" /> +<glyph unicode="." horiz-adv-x="592" d="M86 166q0 92 54.5 142t158.5 50q99 0 152 -50t53 -142q0 -90 -54.5 -140.5t-150.5 -50.5q-99 0 -156 50t-57 141z" /> +<glyph unicode="/" horiz-adv-x="905" d="M10 -20l545 1503h346l-545 -1503h-346z" /> +<glyph unicode="0" d="M72 729q0 390 130 572t398 182q261 0 394.5 -189.5t133.5 -564.5q0 -388 -130 -568.5t-398 -180.5q-262 0 -395 188.5t-133 560.5zM465 729q0 -248 31 -341t104 -93q74 0 104.5 96t30.5 338q0 243 -31 340.5t-104 97.5t-104 -94t-31 -344z" /> +<glyph unicode="1" d="M84 1053l502 409h356v-1462h-401v774q0 141 6 258q-37 -45 -92 -94l-166 -137z" /> +<glyph unicode="2" d="M45 1249q113 101 190 144.5t167.5 66.5t203.5 23q142 0 253.5 -50t173 -142.5t61.5 -207.5q0 -86 -21.5 -159t-66.5 -143.5t-119.5 -148.5t-317.5 -296v-10h553v-326h-1061v260l357 361q153 160 200 218.5t65.5 100.5t18.5 88q0 57 -37 90t-104 33q-69 0 -139.5 -39.5 t-159.5 -116.5z" /> +<glyph unicode="3" d="M70 59v328q96 -49 195.5 -72.5t183.5 -23.5q130 0 189.5 36.5t59.5 114.5q0 60 -31 92.5t-100 49t-180 16.5h-90v297h92q301 0 301 154q0 58 -44.5 86t-119.5 28q-140 0 -290 -94l-164 264q116 80 237.5 114t278.5 34q227 0 356 -90t129 -248q0 -136 -83 -233.5 t-240 -141.5v-6q366 -46 366 -346q0 -204 -161.5 -321t-448.5 -117q-118 0 -218.5 17t-217.5 62z" /> +<glyph unicode="4" d="M35 283v290l608 889h365v-884h161v-295h-161v-283h-390v283h-583zM377 578h241v170q0 48 3.5 129.5t5.5 85.5h-11q-34 -77 -77 -144z" /> +<glyph unicode="5" d="M94 59v324q87 -40 196.5 -66t188.5 -26q110 0 169 46.5t59 137.5q0 84 -60 131t-182 47q-93 0 -201 -35l-145 72l55 772h834v-329h-498l-18 -193q78 15 111 16.5t61 1.5q126 0 227.5 -58.5t158 -165.5t56.5 -247q0 -245 -147.5 -376t-446.5 -131q-256 0 -418 79z" /> +<glyph unicode="6" d="M70 618q0 306 87.5 495.5t258 279.5t420.5 90q89 0 208 -17v-309q-100 19 -217 19q-198 0 -295 -87t-106 -284h12q90 170 289 170q195 0 302.5 -125.5t107.5 -349.5q0 -241 -136 -380.5t-380 -139.5q-259 0 -405 168t-146 470zM463 512q0 -96 41 -157.5t108 -61.5 q63 0 102.5 47.5t39.5 151.5q0 178 -138 178q-68 0 -110.5 -46t-42.5 -112z" /> +<glyph unicode="7" d="M78 1133v327h1055v-233l-515 -1227h-409l502 1133h-633z" /> +<glyph unicode="8" d="M68 385q0 127 61 216.5t205 162.5q-116 78 -169.5 167.5t-53.5 196.5q0 168 131 261.5t362 93.5t359.5 -93t128.5 -264q0 -116 -60.5 -203.5t-191.5 -152.5q162 -92 228.5 -183.5t66.5 -197.5q0 -195 -141 -302t-394 -107q-258 0 -395 104.5t-137 300.5zM430 401 q0 -62 44 -99.5t122 -37.5q176 0 176 129q0 49 -38.5 96.5t-137.5 106.5q-89 -47 -127.5 -94.5t-38.5 -100.5zM481 1092q0 -86 117 -152q71 41 97 75t26 77q0 48 -35 77t-84 29q-51 0 -86 -29.5t-35 -76.5z" /> +<glyph unicode="9" d="M53 958q0 243 138.5 381t379.5 138q268 0 415 -178t147 -506q0 -429 -185 -621t-592 -192q-134 0 -204 10v313q86 -16 172 -16q212 0 327 87.5t125 276.5h-12q-39 -72 -77 -104t-93 -49t-137 -17q-190 0 -297 127t-107 350zM436 963q0 -82 35 -130.5t107 -48.5 q65 0 113 47t48 113q0 89 -44.5 153t-112.5 64q-65 0 -105.5 -47t-40.5 -151z" /> +<glyph unicode=":" horiz-adv-x="592" d="M86 166q0 92 54.5 142t158.5 50q99 0 152 -50t53 -142q0 -90 -54.5 -140.5t-150.5 -50.5q-99 0 -156 50t-57 141zM86 956q0 91 55 141t158 50q99 0 152 -50t53 -141q0 -90 -54 -141t-151 -51q-102 0 -157.5 51t-55.5 141z" /> +<glyph unicode=";" horiz-adv-x="608" d="M57 -285q29 138 58.5 309.5t40.5 274.5h342l14 -23q-97 -381 -176 -561h-279zM92 956q0 91 53.5 141t157.5 50q100 0 153.5 -50.5t53.5 -140.5t-54 -141t-153 -51q-102 0 -156.5 50.5t-54.5 141.5z" /> +<glyph unicode="&#x3c;" horiz-adv-x="1159" d="M72 627v172l1011 506v-297l-620 -283l620 -252v-295z" /> +<glyph unicode="=" horiz-adv-x="1159" d="M72 358v271h1015v-271h-1015zM72 815v268h1015v-268h-1015z" /> +<glyph unicode="&#x3e;" horiz-adv-x="1159" d="M72 178v295l620 252l-620 283v297l1011 -506v-172z" /> +<glyph unicode="?" horiz-adv-x="1034" d="M0 1341q249 142 520 142q223 0 350 -98t127 -267q0 -121 -56.5 -209.5t-180.5 -167.5q-105 -68 -131.5 -99.5t-26.5 -74.5v-51h-307v86q0 98 40 165.5t142 131.5q81 51 116.5 92t35.5 94q0 42 -38 66.5t-99 24.5q-151 0 -353 -107zM252 166q0 92 53.5 142t157.5 50 q100 0 153.5 -50.5t53.5 -141.5t-55.5 -141t-151.5 -50q-99 0 -155 49.5t-56 141.5z" /> +<glyph unicode="@" horiz-adv-x="1837" d="M82 610q0 253 114.5 453.5t316 309t456.5 108.5q234 0 413.5 -89t276 -253.5t96.5 -382.5q0 -141 -48.5 -263t-134.5 -191t-196 -69q-79 0 -143 31.5t-100 87.5h-15q-107 -119 -260 -119q-183 0 -281 107t-98 299q0 141 62 249.5t179 167t271 58.5q81 0 178.5 -16.5 t178.5 -44.5l-21 -422l-2 -94q0 -86 49 -86q52 0 84.5 87t32.5 220q0 239 -135 369t-383 130q-190 0 -330.5 -79t-214.5 -226.5t-74 -345.5q0 -255 142.5 -393.5t402.5 -138.5q116 0 250.5 25t263.5 71v-229q-224 -95 -500 -95q-388 0 -609.5 202.5t-221.5 561.5zM760 641 q0 -100 36.5 -145t96.5 -45q77 0 113 62t47 220l10 156q-40 6 -68 6q-108 0 -171.5 -67t-63.5 -187z" /> +<glyph unicode="A" horiz-adv-x="1487" d="M0 0l477 1468h527l483 -1468h-432l-72 274h-475l-74 -274h-434zM590 598h311l-63 240q-22 80 -53.5 207t-41.5 182q-9 -51 -35.5 -168t-117.5 -461z" /> +<glyph unicode="B" horiz-adv-x="1380" d="M158 0v1462h510q298 0 442.5 -88.5t144.5 -275.5q0 -123 -63 -210t-166 -112v-10q136 -36 197 -120t61 -218q0 -199 -149.5 -313.5t-407.5 -114.5h-569zM553 305h139q185 0 185 156q0 73 -49.5 112t-143.5 39h-131v-307zM553 901h119q85 0 131.5 35t46.5 104 q0 123 -186 123h-111v-262z" /> +<glyph unicode="C" horiz-adv-x="1329" d="M104 727q0 227 85.5 399t246 264.5t377.5 92.5q237 0 453 -103l-121 -311q-81 38 -162 64t-174 26q-141 0 -220 -115.5t-79 -318.5q0 -422 321 -422q97 0 188 27t183 65v-334q-183 -81 -414 -81q-331 0 -507.5 192t-176.5 555z" /> +<glyph unicode="D" horiz-adv-x="1503" d="M158 0v1462h506q352 0 543.5 -180t191.5 -520q0 -366 -201.5 -564t-566.5 -198h-473zM553 324h88q180 0 264 104.5t84 319.5q0 201 -79.5 298t-241.5 97h-115v-819z" /> +<glyph unicode="E" horiz-adv-x="1124" d="M158 0v1462h868v-317h-473v-230h438v-317h-438v-276h473v-322h-868z" /> +<glyph unicode="F" horiz-adv-x="1104" d="M158 0v1462h864v-317h-475v-279h438v-317h-438v-549h-389z" /> +<glyph unicode="G" horiz-adv-x="1516" d="M104 735q0 354 202 551t566 197q138 0 260.5 -26t213.5 -66l-125 -310q-158 78 -347 78q-173 0 -267.5 -112.5t-94.5 -321.5q0 -205 85.5 -312.5t246.5 -107.5q88 0 162 17v229h-261v305h631v-788q-257 -88 -565 -88q-338 0 -522.5 196t-184.5 559z" /> +<glyph unicode="H" horiz-adv-x="1569" d="M158 0v1462h397v-542h459v542h397v-1462h-397v596h-459v-596h-397z" /> +<glyph unicode="I" horiz-adv-x="713" d="M158 0v1462h397v-1462h-397z" /> +<glyph unicode="J" horiz-adv-x="721" d="M-162 -131q32 -6 68 -13.5t78 -7.5q98 0 140 59t42 202v1353h397v-1319q0 -297 -130 -449.5t-390 -152.5q-108 0 -205 21v307z" /> +<glyph unicode="K" horiz-adv-x="1407" d="M158 0v1462h397v-635q30 59 121 187l307 448h432l-461 -655l453 -807h-446l-289 559l-117 -70v-489h-397z" /> +<glyph unicode="L" horiz-adv-x="1192" d="M158 0v1462h395v-1143h563v-319h-958z" /> +<glyph unicode="M" horiz-adv-x="1980" d="M158 0v1462h526l305 -1038h8l299 1038h527v-1462h-363v641q0 50 1.5 111t13.5 299h-9l-295 -1051h-376l-299 1053h-9q21 -269 21 -418v-635h-350z" /> +<glyph unicode="N" horiz-adv-x="1708" d="M158 0v1462h516l532 -1016h6q-14 221 -14 355v661h352v-1462h-518l-534 1030h-9q19 -243 19 -371v-659h-350z" /> +<glyph unicode="O" horiz-adv-x="1632" d="M104 735q0 365 182.5 557.5t530.5 192.5q349 0 529 -191t180 -561q0 -369 -181 -561t-530 -192q-344 0 -527.5 193t-183.5 562zM520 733q0 -424 295 -424q150 0 222.5 103t72.5 321q0 219 -73.5 323.5t-219.5 104.5q-297 0 -297 -428z" /> +<glyph unicode="P" horiz-adv-x="1294" d="M158 0v1462h506q277 0 416 -121t139 -344q0 -245 -144.5 -378.5t-410.5 -133.5h-111v-485h-395zM553 807h72q89 0 141.5 50t52.5 138q0 148 -164 148h-102v-336z" /> +<glyph unicode="Q" horiz-adv-x="1632" d="M104 735q0 365 182.5 557.5t530.5 192.5q349 0 529 -191t180 -561q0 -497 -316 -670l357 -411h-492l-258 325l-1 1v1l-1 1q-344 0 -527.5 193t-183.5 562zM520 733q0 -424 295 -424q150 0 222.5 103t72.5 321q0 219 -73.5 323.5t-219.5 104.5q-297 0 -297 -428z" /> +<glyph unicode="R" horiz-adv-x="1386" d="M158 0v1462h479q596 0 596 -432q0 -254 -248 -393l426 -637h-448l-310 532h-100v-532h-395zM553 829h74q207 0 207 183q0 151 -203 151h-78v-334z" /> +<glyph unicode="S" horiz-adv-x="1182" d="M90 72v352q113 -58 235 -90.5t224 -32.5q88 0 129 30.5t41 78.5q0 30 -16.5 52.5t-53 45.5t-194.5 94q-143 65 -214.5 126t-106 140t-34.5 187q0 202 147 315t404 113q227 0 463 -105l-121 -305q-205 94 -354 94q-77 0 -112 -27t-35 -67q0 -43 44.5 -77t241.5 -124 q189 -85 262.5 -182.5t73.5 -245.5q0 -136 -69 -241.5t-199 -164t-305 -58.5q-146 0 -245 20.5t-206 71.5z" /> +<glyph unicode="T" horiz-adv-x="1210" d="M51 1139v323h1108v-323h-356v-1139h-395v1139h-357z" /> +<glyph unicode="U" horiz-adv-x="1550" d="M150 573v889h397v-858q0 -155 58 -225t171 -70q121 0 175.5 69.5t54.5 227.5v856h395v-880q0 -287 -162.5 -444.5t-468.5 -157.5q-299 0 -459.5 153t-160.5 440z" /> +<glyph unicode="V" horiz-adv-x="1421" d="M0 1462h444l199 -741q62 -247 68 -344q7 70 28 175t37 165l203 745h442l-479 -1462h-465z" /> +<glyph unicode="W" horiz-adv-x="2128" d="M31 1462h381l159 -733q54 -243 74 -387q13 102 46.5 277t62.5 290l129 553h366l125 -553q32 -133 65 -307t44 -260q13 111 71 385l162 735h381l-360 -1462h-467l-140 637q-10 40 -31.5 159t-31.5 199q-8 -65 -26 -161.5t-35.5 -177.5t-145.5 -656h-467z" /> +<glyph unicode="X" horiz-adv-x="1481" d="M4 0l485 748l-456 714h438l264 -452l254 452h451l-463 -745l498 -717h-457l-285 457l-282 -457h-447z" /> +<glyph unicode="Y" horiz-adv-x="1360" d="M0 1462h430l250 -542l252 542h428l-481 -891v-571h-398v559z" /> +<glyph unicode="Z" horiz-adv-x="1251" d="M61 0v244l633 899h-618v319h1108v-243l-633 -900h649v-319h-1139z" /> +<glyph unicode="[" horiz-adv-x="664" d="M117 -344v1847h499v-254h-182v-1339h182v-254h-499zM355 1485z" /> +<glyph unicode="\" horiz-adv-x="905" d="M6 1483h346l545 -1503h-346z" /> +<glyph unicode="]" horiz-adv-x="664" d="M47 -90h182v1339h-182v254h500v-1847h-500v254zM317 1485z" /> +<glyph unicode="^" horiz-adv-x="1075" d="M-16 502l440 966h170l508 -966h-295l-289 577l-124 -291l-124 -286h-286z" /> +<glyph unicode="_" horiz-adv-x="1024" d="M-4 -133h1032v-246h-1032v246z" /> +<glyph unicode="`" horiz-adv-x="1225" d="M264 1548v21h430q52 -70 203 -233l59 -66v-29h-260q-69 44 -203.5 138.5t-228.5 168.5z" /> +<glyph unicode="a" horiz-adv-x="1276" d="M74 346q0 181 126 269.5t365 99.5l189 6v16q0 140 -138 140q-124 0 -315 -84l-113 258q198 102 500 102q218 0 337.5 -108t119.5 -302v-743h-271l-75 150h-8q-79 -98 -161 -134t-212 -36q-160 0 -252 96t-92 270zM473 360q0 -104 111 -104q71 0 121.5 45t50.5 117v88 l-90 -4q-193 -7 -193 -142z" /> +<glyph unicode="b" horiz-adv-x="1317" d="M135 0v1556h391v-352q0 -63 -14 -217h14q57 88 131.5 127t169.5 39q185 0 293.5 -155t108.5 -429q0 -276 -109.5 -432.5t-304.5 -156.5q-63 0 -112 13.5t-87.5 37.5t-89.5 80h-24l-62 -111h-305zM526 555q0 -139 38 -199.5t124 -60.5q69 0 106 70.5t37 207.5 q0 273 -147 273q-82 0 -120 -57t-38 -179v-55z" /> +<glyph unicode="c" horiz-adv-x="1104" d="M86 561q0 282 155 437t441 155q197 0 371 -86l-115 -289q-71 31 -131 49.5t-125 18.5q-95 0 -147 -74t-52 -209q0 -272 201 -272q172 0 330 100v-311q-151 -100 -363 -100q-278 0 -421.5 150t-143.5 431z" /> +<glyph unicode="d" horiz-adv-x="1317" d="M86 565q0 276 111 432t305 156q95 0 166.5 -38t130.5 -128h8q-19 133 -19 266v303h394v-1556h-295l-84 143h-15q-101 -163 -301 -163q-121 0 -211.5 69t-140 203t-49.5 313zM481 559q0 -132 43 -201t123 -69q94 0 132.5 59t41.5 182v31q0 150 -43 213.5t-135 63.5 q-77 0 -119.5 -72.5t-42.5 -206.5z" /> +<glyph unicode="e" horiz-adv-x="1266" d="M86 559q0 287 145 440.5t414 153.5q256 0 395.5 -133.5t139.5 -384.5v-174h-699q4 -95 69.5 -149t178.5 -54q103 0 189.5 19.5t187.5 66.5v-281q-92 -47 -190 -65t-234 -18q-283 0 -439.5 150.5t-156.5 428.5zM489 707h336q-2 82 -46.5 131t-119.5 49q-69 0 -115.5 -43.5 t-54.5 -136.5z" /> +<glyph unicode="f" horiz-adv-x="846" d="M45 840v192l158 96v19q0 224 91.5 322t293.5 98q78 0 147.5 -12t161.5 -42l-84 -253q-72 20 -141 20q-45 0 -65.5 -27.5t-20.5 -89.5v-30h241v-293h-241v-840h-391v840h-150z" /> +<glyph unicode="g" horiz-adv-x="1241" d="M20 -180q0 203 252 262q-52 22 -90.5 71t-38.5 97q0 53 29 93.5t121 96.5q-88 39 -138.5 122t-50.5 202q0 185 126 287t360 102q31 0 107 -7t112 -13h395v-189l-155 -57q32 -58 32 -135q0 -183 -128.5 -284t-383.5 -101q-63 0 -100 8q-14 -26 -14 -49q0 -29 47 -44.5 t123 -15.5h188q381 0 381 -321q0 -207 -176.5 -322t-495.5 -115q-241 0 -371.5 80.5t-130.5 231.5zM350 -141q0 -48 52 -77.5t139 -29.5q142 0 227.5 35.5t85.5 91.5q0 45 -52 63.5t-149 18.5h-153q-63 0 -106.5 -29.5t-43.5 -72.5zM473 762q0 -174 121 -174q56 0 86.5 43 t30.5 129q0 176 -117 176q-121 0 -121 -174z" /> +<glyph unicode="h" horiz-adv-x="1372" d="M135 0v1556h391v-221q0 -150 -16 -342h18q56 88 133 124t179 36q190 0 295.5 -109.5t105.5 -306.5v-737h-393v618q0 228 -135 228q-96 0 -141.5 -80.5t-45.5 -267.5v-498h-391z" /> +<glyph unicode="i" horiz-adv-x="666" d="M127 1415q0 88 49 131t158 43t159 -44t50 -130q0 -172 -209 -172q-207 0 -207 172zM137 0v1133h391v-1133h-391z" /> +<glyph unicode="j" horiz-adv-x="664" d="M-104 -162q64 -18 120 -18q119 0 119 170v1143h391v-1225q0 -187 -109.5 -293.5t-310.5 -106.5q-48 0 -110.5 7.5t-99.5 17.5v305zM125 1415q0 88 49 131t158 43t159 -44t50 -130q0 -172 -209 -172q-207 0 -207 172z" /> +<glyph unicode="k" horiz-adv-x="1350" d="M135 0v1556h393v-612q0 -157 -22 -307h8q71 113 121 176l254 320h436l-393 -482l418 -651h-447l-248 406l-127 -97v-309h-393z" /> +<glyph unicode="l" horiz-adv-x="662" d="M135 0v1556h391v-1556h-391z" /> +<glyph unicode="m" horiz-adv-x="2048" d="M135 0v1133h295l49 -140h23q45 78 130.5 119t194.5 41q245 0 344 -149h31q48 70 133.5 109.5t188.5 39.5q201 0 297 -103t96 -313v-737h-391v616q0 115 -31.5 172.5t-99.5 57.5q-90 0 -132 -77t-42 -241v-528h-392v616q0 115 -30 172.5t-97 57.5q-92 0 -134 -82t-42 -268 v-496h-391z" /> +<glyph unicode="n" horiz-adv-x="1372" d="M135 0v1133h295l49 -140h23q50 80 138.5 120t203.5 40q188 0 292.5 -109t104.5 -307v-737h-391v618q0 113 -32.5 170.5t-104.5 57.5q-99 0 -143 -79t-44 -271v-496h-391z" /> +<glyph unicode="o" horiz-adv-x="1305" d="M86 569q0 277 149.5 430.5t419.5 153.5q167 0 295 -71t197.5 -203.5t69.5 -309.5q0 -278 -149.5 -433.5t-418.5 -155.5q-258 0 -410.5 159t-152.5 430zM483 569q0 -146 39 -222.5t131 -76.5q91 0 128.5 76.5t37.5 222.5q0 145 -38 219t-130 74q-90 0 -129 -73.5 t-39 -219.5z" /> +<glyph unicode="p" horiz-adv-x="1317" d="M135 -492v1625h318l55 -144h18q109 164 301 164q188 0 295 -156t107 -428q0 -274 -111.5 -431.5t-302.5 -157.5q-86 0 -154 28.5t-135 102.5h-18q18 -119 18 -148v-455h-391zM526 571q0 -146 39 -211t123 -65q75 0 109 64.5t34 213.5q0 146 -34 209.5t-113 63.5 q-86 0 -120.5 -61.5t-37.5 -182.5v-31z" /> +<glyph unicode="q" horiz-adv-x="1317" d="M86 565q0 276 110.5 432t301.5 156q205 0 309 -160h8l29 140h338v-1625h-391v469q0 34 12 166h-12q-96 -163 -299 -163q-190 0 -298 156t-108 429zM483 559q0 -148 41 -212t127 -64q89 0 129.5 55t40.5 186v47q0 150 -41 214.5t-135 64.5q-162 0 -162 -291z" /> +<glyph unicode="r" horiz-adv-x="961" d="M135 0v1133h291l61 -181h19q49 90 136.5 145.5t176.5 55.5q51 0 97 -8l22 -4l-35 -369q-48 12 -133 12q-128 0 -186 -58.5t-58 -168.5v-557h-391z" /> +<glyph unicode="s" horiz-adv-x="1092" d="M119 819q0 158 122 246t345 88q112 0 210.5 -24.5t204.5 -71.5l-106 -252q-78 35 -165 59.5t-142 24.5q-96 0 -96 -47q0 -29 33.5 -49.5t193.5 -83.5q119 -49 177.5 -96t86 -110.5t27.5 -154.5q0 -182 -124 -275t-356 -93q-126 0 -219 13.5t-190 49.5v313 q91 -40 199.5 -66t193.5 -26q127 0 127 58q0 30 -35.5 53.5t-206.5 91.5q-156 64 -218 145.5t-62 206.5z" /> +<glyph unicode="t" horiz-adv-x="942" d="M53 840v159l174 123l101 238h256v-227h278v-293h-278v-441q0 -110 106 -110q79 0 189 39v-285q-79 -34 -150.5 -48.5t-167.5 -14.5q-197 0 -284 96.5t-87 296.5v467h-137z" /> +<glyph unicode="u" horiz-adv-x="1372" d="M133 395v738h391v-619q0 -111 31.5 -168t103.5 -57q101 0 144 79.5t43 268.5v496h391v-1133h-295l-49 141h-23q-49 -78 -136.5 -119.5t-205.5 -41.5q-187 0 -291 108.5t-104 306.5z" /> +<glyph unicode="v" horiz-adv-x="1251" d="M0 1133h408l192 -670q1 -5 4 -17t6 -28.5t5.5 -35t2.5 -34.5h7q0 52 18 113l201 672h407l-432 -1133h-387z" /> +<glyph unicode="w" horiz-adv-x="1864" d="M25 1133h385l92 -435q44 -224 51 -372h6q3 92 55 350l105 457h432l96 -463q46 -221 58 -344h6q6 76 20 189.5t31 182.5l100 435h377l-311 -1133h-418l-128 540l-30 163l-20 131h-6q-49 -280 -66 -353l-115 -481h-411z" /> +<glyph unicode="x" horiz-adv-x="1290" d="M10 0l365 578l-346 555h444l172 -318l176 318h445l-355 -555l369 -578h-444l-191 344l-190 -344h-445z" /> +<glyph unicode="y" horiz-adv-x="1249" d="M-2 1133h412l192 -650q14 -51 19 -123h8q8 69 24 121l197 652h399l-448 -1205q-86 -230 -211.5 -325t-327.5 -95q-78 0 -160 17v307q53 -12 121 -12q52 0 91 20t68 56.5t62 119.5z" /> +<glyph unicode="z" horiz-adv-x="1038" d="M49 0v223l469 611h-442v299h889v-242l-449 -592h471v-299h-938z" /> +<glyph unicode="{" horiz-adv-x="887" d="M61 418v301q115 0 180.5 44.5t65.5 125.5v254q0 139 49 208t159.5 100.5t305.5 31.5v-279q-89 -3 -120.5 -13.5t-50.5 -32.5t-19 -60v-271q0 -113 -56.5 -173.5t-183.5 -78.5v-12q128 -20 184 -79t56 -167v-276q0 -39 21 -61t56 -32.5t113 -13.5v-278q-197 0 -307 32 t-158.5 101.5t-48.5 210.5v248q0 80 -67 125t-179 45z" /> +<glyph unicode="|" horiz-adv-x="1042" d="M387 -446v2002h268v-2002h-268z" /> +<glyph unicode="}" horiz-adv-x="887" d="M66 -66q108 4 149 29.5t41 77.5v276q0 108 56 167t184 79v12q-127 18 -183.5 78.5t-56.5 173.5v271q0 39 -19.5 60.5t-50 32t-120.5 13.5v279q196 0 306 -31.5t159 -100.5t49 -208v-254q0 -81 65 -125.5t180 -44.5v-301q-111 0 -178 -45t-67 -125v-248q0 -140 -49 -210 t-159 -102t-306 -32v278z" /> +<glyph unicode="~" horiz-adv-x="1159" d="M72 526v281q104 108 264 108q69 0 130 -13.5t150 -49.5q131 -55 238 -55q50 0 112.5 32t118.5 89v-281q-105 -109 -264 -109q-71 0 -133.5 15t-146.5 49q-131 55 -236 55q-110 0 -233 -121z" /> +<glyph unicode="&#xa1;" horiz-adv-x="594" d="M82 -334l51 946h330l51 -946h-432zM92 963q0 90 54 140t153 50q101 0 156 -50.5t55 -139.5q0 -91 -53.5 -142t-157.5 -51q-102 0 -154.5 50.5t-52.5 142.5z" /> +<glyph unicode="&#xa2;" d="M129 739q0 240 113 388.5t323 189.5v166h207v-154q171 -9 324 -84l-115 -289q-71 31 -131 49.5t-125 18.5q-95 0 -147 -74t-52 -209q0 -272 201 -272q172 0 330 100v-311q-127 -82 -285 -98v-180h-207v186q-212 31 -324 176t-112 397z" /> +<glyph unicode="&#xa3;" d="M102 649v277h166v118q0 215 117 328t338 113q210 0 405 -82l-110 -289q-148 55 -252 55q-58 0 -85.5 -33t-27.5 -104v-106h344v-277h-344v-96q0 -150 -159 -227h671v-326h-1061v313q81 47 109.5 76.5t41.5 67.5t13 94v98h-166z" /> +<glyph unicode="&#xa4;" horiz-adv-x="1159" d="M96 1018l180 182l123 -123q84 41 172 41q91 0 177 -45l120 127l185 -174l-127 -125q41 -76 41 -178q0 -94 -41 -176l121 -119l-179 -178l-120 119q-89 -39 -177 -39q-100 0 -176 37l-119 -115l-178 178l123 119q-41 82 -41 174q0 89 41 176zM436 723q0 -56 40.5 -95.5 t94.5 -39.5q58 0 100 38.5t42 96.5t-42 97.5t-100 39.5q-56 0 -95.5 -40.5t-39.5 -96.5z" /> +<glyph unicode="&#xa5;" d="M8 1462h400l192 -504l193 504h399l-363 -712h195v-211h-242v-117h242v-209h-242v-213h-364v213h-246v209h246v117h-246v211h190z" /> +<glyph unicode="&#xa6;" horiz-adv-x="1042" d="M387 393h268v-839h-268v839zM387 717v839h268v-839h-268z" /> +<glyph unicode="&#xa7;" horiz-adv-x="1024" d="M106 803q0 64 43 125t121 108q-141 102 -141 246q0 137 111 216t295 79q191 0 370 -86l-98 -221q-73 40 -146.5 63t-128.5 23q-108 0 -108 -74q0 -43 45.5 -79t128.5 -70q175 -71 252.5 -152t77.5 -178q0 -77 -32 -137.5t-116 -120.5q125 -94 125 -244 q0 -149 -116.5 -237.5t-319.5 -88.5q-204 0 -352 86v244q79 -44 182 -76t172 -32q139 0 139 96q0 42 -31 72.5t-139 78.5q-141 63 -205.5 112t-96.5 108t-32 139zM397 834q0 -51 44 -91t155 -98q41 47 41 107q0 57 -42 100t-140 84q-58 -32 -58 -102z" /> +<glyph unicode="&#xa8;" horiz-adv-x="1233" d="M223 1413q0 75 46 116.5t124 41.5q79 0 125.5 -42.5t46.5 -115.5q0 -71 -46.5 -113.5t-125.5 -42.5q-78 0 -124 41t-46 115zM702 1413q0 75 46 116.5t126 41.5t126.5 -43t46.5 -115q0 -71 -46.5 -113.5t-126.5 -42.5q-81 0 -126.5 41.5t-45.5 114.5z" /> +<glyph unicode="&#xa9;" horiz-adv-x="1688" d="M92 731q0 200 100 375t275 276t377 101q197 0 370 -97t277 -272t104 -383q0 -204 -100.5 -376.5t-273 -273.5t-377.5 -101q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM256 731q0 -158 79.5 -295.5t215.5 -215t293 -77.5q158 0 294 78.5t215 215t79 294.5 q0 157 -77.5 293t-214 215.5t-296.5 79.5q-158 0 -294.5 -78.5t-215 -215t-78.5 -294.5zM434 735q0 217 113 340t321 123q166 0 322 -78l-92 -205q-106 56 -211 56q-81 0 -126.5 -61t-45.5 -179q0 -128 43.5 -185t134.5 -57q138 0 258 68v-231q-126 -64 -272 -64 q-212 0 -328.5 124t-116.5 349z" /> +<glyph unicode="&#xaa;" horiz-adv-x="813" d="M49 967q0 116 77 171t267 64l88 4v6q0 41 -25.5 58.5t-76.5 17.5q-57 0 -107.5 -15t-103.5 -40l-76 166q108 51 180.5 65.5t163.5 14.5q139 0 218 -75.5t79 -213.5v-449h-162l-45 127q-48 -76 -104.5 -107.5t-138.5 -31.5q-109 0 -171.5 63.5t-62.5 174.5zM301 979 q0 -32 18 -50t52 -18q50 0 80 38.5t30 97.5v22l-84 -6q-96 -6 -96 -84z" /> +<glyph unicode="&#xab;" horiz-adv-x="1395" d="M74 561v27l389 483l280 -149l-272 -347l272 -348l-280 -147zM649 561v27l387 483l283 -149l-275 -347l275 -348l-283 -147z" /> +<glyph unicode="&#xac;" horiz-adv-x="1159" d="M72 588v268h1013v-618h-270v350h-743z" /> +<glyph unicode="&#xad;" horiz-adv-x="651" d="M43 393v312h565v-312h-565z" /> +<glyph unicode="&#xae;" horiz-adv-x="1688" d="M92 731q0 200 100 375t275 276t377 101q197 0 370 -97t277 -272t104 -383q0 -204 -100.5 -376.5t-273 -273.5t-377.5 -101q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM256 731q0 -158 79.5 -295.5t215.5 -215t293 -77.5q158 0 294 78.5t215 215t79 294.5 q0 157 -77.5 293t-214 215.5t-296.5 79.5q-158 0 -294.5 -78.5t-215 -215t-78.5 -294.5zM506 313v875h291q407 0 407 -270q0 -87 -33 -146.5t-108 -95.5l194 -363h-290l-146 320h-35v-320h-280zM786 809h11q58 0 91.5 21.5t33.5 76.5q0 47 -27.5 66.5t-95.5 19.5h-13v-184z " /> +<glyph unicode="&#xaf;" horiz-adv-x="1024" d="M-6 1556v246h1036v-246h-1036z" /> +<glyph unicode="&#xb0;" horiz-adv-x="864" d="M63 1114q0 97 49 182.5t135 136t185 50.5t185 -50.5t135 -135.5t49 -183q0 -97 -48.5 -181t-134 -133.5t-186.5 -49.5q-99 0 -185 49t-135 133t-49 182zM301 1114q0 -50 38.5 -88.5t92.5 -38.5t92.5 39t38.5 88q0 52 -37.5 92.5t-93.5 40.5t-93.5 -40.5t-37.5 -92.5z" /> +<glyph unicode="&#xb1;" horiz-adv-x="1159" d="M72 0v268h1013v-268h-1013zM72 684v268h372v367h269v-367h372v-268h-372v-360h-269v360h-372z" /> +<glyph unicode="&#xb2;" horiz-adv-x="817" d="M61 1350q80 73 167.5 104t203.5 31q142 0 219.5 -63t77.5 -175q0 -46 -13 -87t-40.5 -84.5t-74.5 -91t-198 -173.5h347v-225h-674v207l215 213q84 84 116.5 129t32.5 79q0 58 -65 58q-81 0 -172 -88z" /> +<glyph unicode="&#xb3;" horiz-adv-x="817" d="M63 1366q149 115 343 115q146 0 232.5 -57.5t86.5 -157.5q0 -78 -37 -132.5t-125 -86.5v-9q97 -24 144 -76t47 -139q0 -120 -98 -187t-277 -67q-185 0 -309 70v233q117 -81 297 -81q116 0 116 67q0 41 -32.5 56.5t-102.5 15.5h-104v194h80q71 0 105 18.5t34 59.5 q0 25 -21 46.5t-71 21.5t-94 -17t-97 -57z" /> +<glyph unicode="&#xb4;" horiz-adv-x="1225" d="M264 1241v29q154 165 195.5 213t68.5 86h428v-21q-80 -64 -220 -163t-212 -144h-260z" /> +<glyph unicode="&#xb5;" horiz-adv-x="1376" d="M135 -492v1625h391v-615q0 -115 33.5 -172t112.5 -57q93 0 134.5 83t41.5 265v496h393v-1133h-293l-53 152h-16q-34 -88 -90.5 -130t-122.5 -42q-56 0 -90 20t-62 63q12 -90 12 -235v-320h-391z" /> +<glyph unicode="&#xb6;" horiz-adv-x="1317" d="M102 1042q0 256 107.5 385t343.5 129h633v-1816h-191v1587h-157v-1587h-191v819q-54 -18 -125 -18q-216 0 -318 125t-102 376z" /> +<glyph unicode="&#xb7;" horiz-adv-x="592" d="M86 723q0 92 54.5 142t158.5 50q99 0 152 -50t53 -142q0 -90 -54.5 -141.5t-150.5 -51.5q-100 0 -156.5 51t-56.5 142z" /> +<glyph unicode="&#xb8;" horiz-adv-x="383" d="M-90 -258q83 -27 147 -27q52 0 52 47q0 33 -41 58.5t-107 40.5l72 139h203l-9 -29q96 -39 133 -92.5t37 -130.5q0 -109 -75 -174.5t-199 -65.5q-136 0 -213 29v205z" /> +<glyph unicode="&#xb9;" horiz-adv-x="817" d="M57 1188l340 274h219v-876h-282v356q0 35 3.5 118t6.5 99q-9 -19 -31.5 -43t-109.5 -98z" /> +<glyph unicode="&#xba;" horiz-adv-x="803" d="M49 1104q0 177 94.5 276t259.5 99q157 0 255 -103t98 -272q0 -174 -95.5 -274.5t-261.5 -100.5q-159 0 -254.5 102.5t-95.5 272.5zM301 1104q0 -87 24 -129.5t76 -42.5q99 0 99 172q0 174 -99 174q-100 0 -100 -174z" /> +<glyph unicode="&#xbb;" horiz-adv-x="1395" d="M76 227l272 348l-272 347l282 149l387 -483v-27l-387 -481zM649 227l275 348l-275 347l285 149l387 -483v-27l-387 -481z" /> +<glyph unicode="&#xbc;" horiz-adv-x="1919" d="M1028 140v188l350 555h295v-542h125v-201h-125v-139h-275v139h-370zM1241 341h157v166q0 69 7 135q-40 -100 -62 -133zM357 0l753 1462h302l-754 -1462h-301zM-12 1188l340 274h219v-876h-282v356q0 35 3.5 118t6.5 99q-9 -19 -31.5 -43t-109.5 -98z" /> +<glyph unicode="&#xbd;" horiz-adv-x="1921" d="M1140 765q80 73 167.5 104t203.5 31q142 0 219.5 -63t77.5 -175q0 -46 -13 -87t-40.5 -84.5t-74.5 -91t-198 -173.5h347v-225h-674v207l215 213q84 84 116.5 129t32.5 79q0 58 -65 58q-81 0 -172 -88zM381 0l753 1462h302l-754 -1462h-301zM-12 1188l340 274h219v-876 h-282v356q0 35 3.5 118t6.5 99q-9 -19 -31.5 -43t-109.5 -98z" /> +<glyph unicode="&#xbe;" horiz-adv-x="1921" d="M1100 140v188l350 555h295v-542h125v-201h-125v-139h-275v139h-370zM1313 341h157v166q0 69 7 135q-40 -100 -62 -133zM83 1366q149 115 343 115q146 0 232.5 -57.5t86.5 -157.5q0 -78 -37 -132.5t-125 -86.5v-9q97 -24 144 -76t47 -139q0 -120 -98 -187t-277 -67 q-185 0 -309 70v233q117 -81 297 -81q116 0 116 67q0 41 -32.5 56.5t-102.5 15.5h-104v194h80q71 0 105 18.5t34 59.5q0 25 -21 46.5t-71 21.5t-94 -17t-97 -57zM465 0l753 1462h302l-754 -1462h-301z" /> +<glyph unicode="&#xbf;" horiz-adv-x="1034" d="M37 10q0 120 55 208t182 169q100 64 129 97t29 77v51h307v-86q0 -98 -40 -165.5t-142 -131.5q-57 -36 -90 -66t-47 -55.5t-14 -64.5q0 -42 37.5 -66t99.5 -24q148 0 352 106l139 -272q-243 -141 -520 -141q-223 0 -350 98t-127 266zM365 963q0 90 54 140t152 50 q101 0 156 -49.5t55 -140.5q0 -93 -53 -143t-158 -50q-101 0 -153.5 50t-52.5 143z" /> +<glyph unicode="&#xc0;" horiz-adv-x="1487" d="M0 0l477 1468h527l483 -1468h-432l-72 274h-475l-74 -274h-434zM590 598h311l-63 240q-22 80 -53.5 207t-41.5 182q-9 -51 -35.5 -168t-117.5 -461zM272 1886v21h430q52 -70 203 -233l59 -66v-29h-260q-69 44 -203.5 138.5t-228.5 168.5z" /> +<glyph unicode="&#xc1;" horiz-adv-x="1487" d="M0 0l477 1468h527l483 -1468h-432l-72 274h-475l-74 -274h-434zM590 598h311l-63 240q-22 80 -53.5 207t-41.5 182q-9 -51 -35.5 -168t-117.5 -461zM532 1579v29q154 165 195.5 213t68.5 86h428v-21q-80 -64 -220 -163t-212 -144h-260z" /> +<glyph unicode="&#xc2;" horiz-adv-x="1487" d="M0 0l477 1468h527l483 -1468h-432l-72 274h-475l-74 -274h-434zM590 598h311l-63 240q-22 80 -53.5 207t-41.5 182q-9 -51 -35.5 -168t-117.5 -461zM295 1579v29q69 65 144.5 153t113.5 146h393q94 -137 256 -299v-29h-254q-84 48 -201 150q-125 -107 -194 -150h-258z " /> +<glyph unicode="&#xc3;" horiz-adv-x="1487" d="M0 0l477 1468h527l483 -1468h-432l-72 274h-475l-74 -274h-434zM590 598h311l-63 240q-22 80 -53.5 207t-41.5 182q-9 -51 -35.5 -168t-117.5 -461zM330 1575q11 175 72 258.5t180 83.5q38 0 81 -15t87 -33t87 -33t81 -15q29 0 46 25t26 73h182q-11 -167 -74 -254.5 t-172 -87.5q-45 0 -90.5 15t-89.5 33t-85.5 33t-78.5 15q-54 0 -72 -98h-180z" /> +<glyph unicode="&#xc4;" horiz-adv-x="1487" d="M0 0l477 1468h527l483 -1468h-432l-72 274h-475l-74 -274h-434zM590 598h311l-63 240q-22 80 -53.5 207t-41.5 182q-9 -51 -35.5 -168t-117.5 -461zM352 1751q0 75 46 116.5t124 41.5q79 0 125.5 -42.5t46.5 -115.5q0 -71 -46.5 -113.5t-125.5 -42.5q-78 0 -124 41 t-46 115zM831 1751q0 75 46 116.5t126 41.5t126.5 -43t46.5 -115q0 -71 -46.5 -113.5t-126.5 -42.5q-81 0 -126.5 41.5t-45.5 114.5z" /> +<glyph unicode="&#xc5;" horiz-adv-x="1487" d="M0 0l477 1468h527l483 -1468h-432l-72 274h-475l-74 -274h-434zM590 598h311l-63 240q-22 80 -53.5 207t-41.5 182q-9 -51 -35.5 -168t-117.5 -461zM475 1614q0 116 71.5 185t192.5 69q118 0 195 -70t77 -182q0 -113 -76 -183.5t-196 -70.5q-121 0 -192.5 68.5 t-71.5 183.5zM655 1614q0 -37 21 -60.5t63 -23.5q35 0 59.5 23.5t24.5 60.5q0 38 -24.5 61t-59.5 23t-59.5 -23t-24.5 -61z" /> +<glyph unicode="&#xc6;" horiz-adv-x="1937" d="M-10 0l628 1462h1221v-317h-473v-230h438v-317h-438v-276h473v-322h-870v274h-437l-100 -274h-442zM653 602h316v526h-111z" /> +<glyph unicode="&#xc7;" horiz-adv-x="1329" d="M104 727q0 227 85.5 399t246 264.5t377.5 92.5q237 0 453 -103l-121 -311q-81 38 -162 64t-174 26q-141 0 -220 -115.5t-79 -318.5q0 -422 321 -422q97 0 188 27t183 65v-334q-183 -81 -414 -81q-331 0 -507.5 192t-176.5 555zM477 -258q83 -27 147 -27q52 0 52 47 q0 33 -41 58.5t-107 40.5l72 139h203l-9 -29q96 -39 133 -92.5t37 -130.5q0 -109 -75 -174.5t-199 -65.5q-136 0 -213 29v205z" /> +<glyph unicode="&#xc8;" horiz-adv-x="1124" d="M158 0v1462h868v-317h-473v-230h438v-317h-438v-276h473v-322h-868zM154 1886v21h430q52 -70 203 -233l59 -66v-29h-260q-69 44 -203.5 138.5t-228.5 168.5z" /> +<glyph unicode="&#xc9;" horiz-adv-x="1124" d="M158 0v1462h868v-317h-473v-230h438v-317h-438v-276h473v-322h-868zM362 1579v29q154 165 195.5 213t68.5 86h428v-21q-80 -64 -220 -163t-212 -144h-260z" /> +<glyph unicode="&#xca;" horiz-adv-x="1124" d="M158 0v1462h868v-317h-473v-230h438v-317h-438v-276h473v-322h-868zM151 1579v29q69 65 144.5 153t113.5 146h393q94 -137 256 -299v-29h-254q-84 48 -201 150q-125 -107 -194 -150h-258z" /> +<glyph unicode="&#xcb;" horiz-adv-x="1124" d="M158 0v1462h868v-317h-473v-230h438v-317h-438v-276h473v-322h-868zM187 1751q0 75 46 116.5t124 41.5q79 0 125.5 -42.5t46.5 -115.5q0 -71 -46.5 -113.5t-125.5 -42.5q-78 0 -124 41t-46 115zM666 1751q0 75 46 116.5t126 41.5t126.5 -43t46.5 -115q0 -71 -46.5 -113.5 t-126.5 -42.5q-81 0 -126.5 41.5t-45.5 114.5z" /> +<glyph unicode="&#xcc;" horiz-adv-x="713" d="M158 0v1462h397v-1462h-397zM-116 1886v21h430q52 -70 203 -233l59 -66v-29h-260q-69 44 -203.5 138.5t-228.5 168.5z" /> +<glyph unicode="&#xcd;" horiz-adv-x="713" d="M158 0v1462h397v-1462h-397zM156 1579v29q154 165 195.5 213t68.5 86h428v-21q-80 -64 -220 -163t-212 -144h-260z" /> +<glyph unicode="&#xce;" horiz-adv-x="713" d="M158 0v1462h397v-1462h-397zM-95 1579v29q69 65 144.5 153t113.5 146h393q94 -137 256 -299v-29h-254q-84 48 -201 150q-125 -107 -194 -150h-258z" /> +<glyph unicode="&#xcf;" horiz-adv-x="713" d="M158 0v1462h397v-1462h-397zM-55 1751q0 75 46 116.5t124 41.5q79 0 125.5 -42.5t46.5 -115.5q0 -71 -46.5 -113.5t-125.5 -42.5q-78 0 -124 41t-46 115zM424 1751q0 75 46 116.5t126 41.5t126.5 -43t46.5 -115q0 -71 -46.5 -113.5t-126.5 -42.5q-81 0 -126.5 41.5 t-45.5 114.5z" /> +<glyph unicode="&#xd0;" horiz-adv-x="1503" d="M31 563v320h127v579h506q352 0 543.5 -180t191.5 -520q0 -366 -201.5 -564t-566.5 -198h-473v563h-127zM553 324h88q180 0 264 104.5t84 319.5q0 201 -79.5 298t-241.5 97h-115v-260h211v-320h-211v-239z" /> +<glyph unicode="&#xd1;" horiz-adv-x="1708" d="M158 0v1462h516l532 -1016h6q-14 221 -14 355v661h352v-1462h-518l-534 1030h-9q19 -243 19 -371v-659h-350zM434 1575q11 175 72 258.5t180 83.5q38 0 81 -15t87 -33t87 -33t81 -15q29 0 46 25t26 73h182q-11 -167 -74 -254.5t-172 -87.5q-45 0 -90.5 15t-89.5 33 t-85.5 33t-78.5 15q-54 0 -72 -98h-180z" /> +<glyph unicode="&#xd2;" horiz-adv-x="1632" d="M104 735q0 365 182.5 557.5t530.5 192.5q349 0 529 -191t180 -561q0 -369 -181 -561t-530 -192q-344 0 -527.5 193t-183.5 562zM520 733q0 -424 295 -424q150 0 222.5 103t72.5 321q0 219 -73.5 323.5t-219.5 104.5q-297 0 -297 -428zM397 1886v21h430q52 -70 203 -233 l59 -66v-29h-260q-69 44 -203.5 138.5t-228.5 168.5z" /> +<glyph unicode="&#xd3;" horiz-adv-x="1632" d="M104 735q0 365 182.5 557.5t530.5 192.5q349 0 529 -191t180 -561q0 -369 -181 -561t-530 -192q-344 0 -527.5 193t-183.5 562zM520 733q0 -424 295 -424q150 0 222.5 103t72.5 321q0 219 -73.5 323.5t-219.5 104.5q-297 0 -297 -428zM583 1579v29q154 165 195.5 213 t68.5 86h428v-21q-80 -64 -220 -163t-212 -144h-260z" /> +<glyph unicode="&#xd4;" horiz-adv-x="1632" d="M104 735q0 365 182.5 557.5t530.5 192.5q349 0 529 -191t180 -561q0 -369 -181 -561t-530 -192q-344 0 -527.5 193t-183.5 562zM520 733q0 -424 295 -424q150 0 222.5 103t72.5 321q0 219 -73.5 323.5t-219.5 104.5q-297 0 -297 -428zM363 1579v29q69 65 144.5 153 t113.5 146h393q94 -137 256 -299v-29h-254q-84 48 -201 150q-125 -107 -194 -150h-258z" /> +<glyph unicode="&#xd5;" horiz-adv-x="1632" d="M104 735q0 365 182.5 557.5t530.5 192.5q349 0 529 -191t180 -561q0 -369 -181 -561t-530 -192q-344 0 -527.5 193t-183.5 562zM520 733q0 -424 295 -424q150 0 222.5 103t72.5 321q0 219 -73.5 323.5t-219.5 104.5q-297 0 -297 -428zM401 1575q11 175 72 258.5t180 83.5 q38 0 81 -15t87 -33t87 -33t81 -15q29 0 46 25t26 73h182q-11 -167 -74 -254.5t-172 -87.5q-45 0 -90.5 15t-89.5 33t-85.5 33t-78.5 15q-54 0 -72 -98h-180z" /> +<glyph unicode="&#xd6;" horiz-adv-x="1632" d="M104 735q0 365 182.5 557.5t530.5 192.5q349 0 529 -191t180 -561q0 -369 -181 -561t-530 -192q-344 0 -527.5 193t-183.5 562zM520 733q0 -424 295 -424q150 0 222.5 103t72.5 321q0 219 -73.5 323.5t-219.5 104.5q-297 0 -297 -428zM403 1751q0 75 46 116.5t124 41.5 q79 0 125.5 -42.5t46.5 -115.5q0 -71 -46.5 -113.5t-125.5 -42.5q-78 0 -124 41t-46 115zM882 1751q0 75 46 116.5t126 41.5t126.5 -43t46.5 -115q0 -71 -46.5 -113.5t-126.5 -42.5q-81 0 -126.5 41.5t-45.5 114.5z" /> +<glyph unicode="&#xd7;" horiz-adv-x="1159" d="M121 991l182 189l270 -267l275 267l188 -183l-274 -274l270 -272l-184 -185l-275 271l-270 -269l-180 187l264 268z" /> +<glyph unicode="&#xd8;" horiz-adv-x="1632" d="M104 735q0 365 182.5 557.5t530.5 192.5q191 0 330 -55l76 118l190 -114l-82 -125q195 -189 195 -576q0 -369 -181 -561t-530 -192q-177 0 -307 43l-84 -132l-193 125l84 125q-211 194 -211 594zM520 733q0 -155 29 -239l403 639q-68 28 -135 28q-297 0 -297 -428z M698 324q54 -15 117 -15q150 0 222.5 103t72.5 321q0 125 -18 211z" /> +<glyph unicode="&#xd9;" horiz-adv-x="1550" d="M150 573v889h397v-858q0 -155 58 -225t171 -70q121 0 175.5 69.5t54.5 227.5v856h395v-880q0 -287 -162.5 -444.5t-468.5 -157.5q-299 0 -459.5 153t-160.5 440zM280 1886v21h430q52 -70 203 -233l59 -66v-29h-260q-69 44 -203.5 138.5t-228.5 168.5z" /> +<glyph unicode="&#xda;" horiz-adv-x="1550" d="M150 573v889h397v-858q0 -155 58 -225t171 -70q121 0 175.5 69.5t54.5 227.5v856h395v-880q0 -287 -162.5 -444.5t-468.5 -157.5q-299 0 -459.5 153t-160.5 440zM561 1579v29q154 165 195.5 213t68.5 86h428v-21q-80 -64 -220 -163t-212 -144h-260z" /> +<glyph unicode="&#xdb;" horiz-adv-x="1550" d="M150 573v889h397v-858q0 -155 58 -225t171 -70q121 0 175.5 69.5t54.5 227.5v856h395v-880q0 -287 -162.5 -444.5t-468.5 -157.5q-299 0 -459.5 153t-160.5 440zM322 1579v29q69 65 144.5 153t113.5 146h393q94 -137 256 -299v-29h-254q-84 48 -201 150 q-125 -107 -194 -150h-258z" /> +<glyph unicode="&#xdc;" horiz-adv-x="1550" d="M150 573v889h397v-858q0 -155 58 -225t171 -70q121 0 175.5 69.5t54.5 227.5v856h395v-880q0 -287 -162.5 -444.5t-468.5 -157.5q-299 0 -459.5 153t-160.5 440zM362 1751q0 75 46 116.5t124 41.5q79 0 125.5 -42.5t46.5 -115.5q0 -71 -46.5 -113.5t-125.5 -42.5 q-78 0 -124 41t-46 115zM841 1751q0 75 46 116.5t126 41.5t126.5 -43t46.5 -115q0 -71 -46.5 -113.5t-126.5 -42.5q-81 0 -126.5 41.5t-45.5 114.5z" /> +<glyph unicode="&#xdd;" horiz-adv-x="1360" d="M0 1462h430l250 -542l252 542h428l-481 -891v-571h-398v559zM471 1579v29q154 165 195.5 213t68.5 86h428v-21q-80 -64 -220 -163t-212 -144h-260z" /> +<glyph unicode="&#xde;" horiz-adv-x="1284" d="M158 0v1462h395v-213h111q277 0 416 -121t139 -344q0 -245 -144.5 -378.5t-410.5 -133.5h-111v-272h-395zM553 594h72q89 0 141.5 50t52.5 138q0 148 -164 148h-102v-336z" /> +<glyph unicode="&#xdf;" horiz-adv-x="1536" d="M135 0v1100q0 215 167 341t446 126q276 0 433.5 -99.5t157.5 -277.5q0 -57 -20 -103.5t-49.5 -84t-64.5 -66.5t-64.5 -52t-49.5 -41t-20 -32q0 -23 24.5 -44t93.5 -58q169 -95 228.5 -173t59.5 -202q0 -174 -115 -264t-338 -90q-136 0 -221.5 12.5t-149.5 46.5v291 q49 -30 131.5 -55t147.5 -25q61 0 99 23.5t38 62.5q0 28 -14.5 47t-50.5 42.5t-121 68.5q-126 67 -175 124.5t-49 137.5q0 122 140 218q75 52 107 91.5t32 83.5q0 51 -49.5 85t-140.5 34q-222 0 -222 -209v-1059h-391z" /> +<glyph unicode="&#xe0;" horiz-adv-x="1276" d="M74 346q0 181 126 269.5t365 99.5l189 6v16q0 140 -138 140q-124 0 -315 -84l-113 258q198 102 500 102q218 0 337.5 -108t119.5 -302v-743h-271l-75 150h-8q-79 -98 -161 -134t-212 -36q-160 0 -252 96t-92 270zM473 360q0 -104 111 -104q71 0 121.5 45t50.5 117v88 l-90 -4q-193 -7 -193 -142zM204 1548v21h430q52 -70 203 -233l59 -66v-29h-260q-69 44 -203.5 138.5t-228.5 168.5z" /> +<glyph unicode="&#xe1;" horiz-adv-x="1276" d="M74 346q0 181 126 269.5t365 99.5l189 6v16q0 140 -138 140q-124 0 -315 -84l-113 258q198 102 500 102q218 0 337.5 -108t119.5 -302v-743h-271l-75 150h-8q-79 -98 -161 -134t-212 -36q-160 0 -252 96t-92 270zM473 360q0 -104 111 -104q71 0 121.5 45t50.5 117v88 l-90 -4q-193 -7 -193 -142zM434 1241v29q154 165 195.5 213t68.5 86h428v-21q-80 -64 -220 -163t-212 -144h-260z" /> +<glyph unicode="&#xe2;" horiz-adv-x="1276" d="M74 346q0 181 126 269.5t365 99.5l189 6v16q0 140 -138 140q-124 0 -315 -84l-113 258q198 102 500 102q218 0 337.5 -108t119.5 -302v-743h-271l-75 150h-8q-79 -98 -161 -134t-212 -36q-160 0 -252 96t-92 270zM473 360q0 -104 111 -104q71 0 121.5 45t50.5 117v88 l-90 -4q-193 -7 -193 -142zM197 1238v29q69 65 144.5 153t113.5 146h393q94 -137 256 -299v-29h-254q-84 48 -201 150q-125 -107 -194 -150h-258z" /> +<glyph unicode="&#xe3;" horiz-adv-x="1276" d="M74 346q0 181 126 269.5t365 99.5l189 6v16q0 140 -138 140q-124 0 -315 -84l-113 258q198 102 500 102q218 0 337.5 -108t119.5 -302v-743h-271l-75 150h-8q-79 -98 -161 -134t-212 -36q-160 0 -252 96t-92 270zM473 360q0 -104 111 -104q71 0 121.5 45t50.5 117v88 l-90 -4q-193 -7 -193 -142zM244 1237q11 175 72 258.5t180 83.5q38 0 81 -15t87 -33t87 -33t81 -15q29 0 46 25t26 73h182q-11 -167 -74 -254.5t-172 -87.5q-45 0 -90.5 15t-89.5 33t-85.5 33t-78.5 15q-54 0 -72 -98h-180z" /> +<glyph unicode="&#xe4;" horiz-adv-x="1276" d="M74 346q0 181 126 269.5t365 99.5l189 6v16q0 140 -138 140q-124 0 -315 -84l-113 258q198 102 500 102q218 0 337.5 -108t119.5 -302v-743h-271l-75 150h-8q-79 -98 -161 -134t-212 -36q-160 0 -252 96t-92 270zM473 360q0 -104 111 -104q71 0 121.5 45t50.5 117v88 l-90 -4q-193 -7 -193 -142zM268 1413q0 75 46 116.5t124 41.5q79 0 125.5 -42.5t46.5 -115.5q0 -71 -46.5 -113.5t-125.5 -42.5q-78 0 -124 41t-46 115zM747 1413q0 75 46 116.5t126 41.5t126.5 -43t46.5 -115q0 -71 -46.5 -113.5t-126.5 -42.5q-81 0 -126.5 41.5 t-45.5 114.5z" /> +<glyph unicode="&#xe5;" horiz-adv-x="1276" d="M74 346q0 181 126 269.5t365 99.5l189 6v16q0 140 -138 140q-124 0 -315 -84l-113 258q198 102 500 102q218 0 337.5 -108t119.5 -302v-743h-271l-75 150h-8q-79 -98 -161 -134t-212 -36q-160 0 -252 96t-92 270zM473 360q0 -104 111 -104q71 0 121.5 45t50.5 117v88 l-90 -4q-193 -7 -193 -142zM389 1489q0 116 71.5 185t192.5 69q118 0 195 -70t77 -182q0 -113 -76 -183.5t-196 -70.5q-121 0 -192.5 68.5t-71.5 183.5zM569 1489q0 -37 21 -60.5t63 -23.5q35 0 59.5 23.5t24.5 60.5q0 38 -24.5 61t-59.5 23t-59.5 -23t-24.5 -61z" /> +<glyph unicode="&#xe6;" horiz-adv-x="1915" d="M74 352q0 345 497 363l183 6v18q0 138 -136 138q-138 0 -313 -80l-110 256q190 100 454 100q201 0 336 -94q70 49 153 71.5t199 22.5q229 0 360.5 -136.5t131.5 -383.5v-172h-696q4 -90 74 -146.5t186 -56.5q194 0 364 86v-281q-94 -48 -191 -65.5t-225 -17.5 q-280 0 -430 190q-80 -83 -141.5 -120.5t-138.5 -53.5t-197 -16q-162 0 -261 101.5t-99 270.5zM473 356q0 -100 113 -100q69 0 119.5 45t50.5 117v88l-84 -4q-106 -4 -152.5 -38.5t-46.5 -107.5zM1139 707h340q-2 82 -48 131t-116 49q-162 0 -176 -180z" /> +<glyph unicode="&#xe7;" horiz-adv-x="1104" d="M86 561q0 282 155 437t441 155q197 0 371 -86l-115 -289q-71 31 -131 49.5t-125 18.5q-95 0 -147 -74t-52 -209q0 -272 201 -272q172 0 330 100v-311q-151 -100 -363 -100q-278 0 -421.5 150t-143.5 431zM361 -258q83 -27 147 -27q52 0 52 47q0 33 -41 58.5t-107 40.5 l72 139h203l-9 -29q96 -39 133 -92.5t37 -130.5q0 -109 -75 -174.5t-199 -65.5q-136 0 -213 29v205z" /> +<glyph unicode="&#xe8;" horiz-adv-x="1266" d="M86 559q0 287 145 440.5t414 153.5q256 0 395.5 -133.5t139.5 -384.5v-174h-699q4 -95 69.5 -149t178.5 -54q103 0 189.5 19.5t187.5 66.5v-281q-92 -47 -190 -65t-234 -18q-283 0 -439.5 150.5t-156.5 428.5zM489 707h336q-2 82 -46.5 131t-119.5 49q-69 0 -115.5 -43.5 t-54.5 -136.5zM189 1548v21h430q52 -70 203 -233l59 -66v-29h-260q-69 44 -203.5 138.5t-228.5 168.5z" /> +<glyph unicode="&#xe9;" horiz-adv-x="1266" d="M86 559q0 287 145 440.5t414 153.5q256 0 395.5 -133.5t139.5 -384.5v-174h-699q4 -95 69.5 -149t178.5 -54q103 0 189.5 19.5t187.5 66.5v-281q-92 -47 -190 -65t-234 -18q-283 0 -439.5 150.5t-156.5 428.5zM489 707h336q-2 82 -46.5 131t-119.5 49q-69 0 -115.5 -43.5 t-54.5 -136.5zM471 1241v29q154 165 195.5 213t68.5 86h428v-21q-80 -64 -220 -163t-212 -144h-260z" /> +<glyph unicode="&#xea;" horiz-adv-x="1266" d="M86 559q0 287 145 440.5t414 153.5q256 0 395.5 -133.5t139.5 -384.5v-174h-699q4 -95 69.5 -149t178.5 -54q103 0 189.5 19.5t187.5 66.5v-281q-92 -47 -190 -65t-234 -18q-283 0 -439.5 150.5t-156.5 428.5zM489 707h336q-2 82 -46.5 131t-119.5 49q-69 0 -115.5 -43.5 t-54.5 -136.5zM205 1241v29q69 65 144.5 153t113.5 146h393q94 -137 256 -299v-29h-254q-84 48 -201 150q-125 -107 -194 -150h-258z" /> +<glyph unicode="&#xeb;" horiz-adv-x="1266" d="M86 559q0 287 145 440.5t414 153.5q256 0 395.5 -133.5t139.5 -384.5v-174h-699q4 -95 69.5 -149t178.5 -54q103 0 189.5 19.5t187.5 66.5v-281q-92 -47 -190 -65t-234 -18q-283 0 -439.5 150.5t-156.5 428.5zM489 707h336q-2 82 -46.5 131t-119.5 49q-69 0 -115.5 -43.5 t-54.5 -136.5zM252 1413q0 75 46 116.5t124 41.5q79 0 125.5 -42.5t46.5 -115.5q0 -71 -46.5 -113.5t-125.5 -42.5q-78 0 -124 41t-46 115zM731 1413q0 75 46 116.5t126 41.5t126.5 -43t46.5 -115q0 -71 -46.5 -113.5t-126.5 -42.5q-81 0 -126.5 41.5t-45.5 114.5z" /> +<glyph unicode="&#xec;" horiz-adv-x="666" d="M137 0v1133h391v-1133h-391zM-130 1548v21h430q52 -70 203 -233l59 -66v-29h-260q-69 44 -203.5 138.5t-228.5 168.5z" /> +<glyph unicode="&#xed;" horiz-adv-x="666" d="M137 0v1133h391v-1133h-391zM107 1241v29q154 165 195.5 213t68.5 86h428v-21q-80 -64 -220 -163t-212 -144h-260z" /> +<glyph unicode="&#xee;" horiz-adv-x="666" d="M137 0v1133h391v-1133h-391zM-120 1241v29q69 65 144.5 153t113.5 146h393q94 -137 256 -299v-29h-254q-84 48 -201 150q-125 -107 -194 -150h-258z" /> +<glyph unicode="&#xef;" horiz-adv-x="666" d="M137 0v1133h391v-1133h-391zM-61 1413q0 75 46 116.5t124 41.5q79 0 125.5 -42.5t46.5 -115.5q0 -71 -46.5 -113.5t-125.5 -42.5q-78 0 -124 41t-46 115zM418 1413q0 75 46 116.5t126 41.5t126.5 -43t46.5 -115q0 -71 -46.5 -113.5t-126.5 -42.5q-81 0 -126.5 41.5 t-45.5 114.5z" /> +<glyph unicode="&#xf0;" horiz-adv-x="1313" d="M88 498q0 239 130.5 377.5t348.5 138.5q192 0 244 -84l8 4q-67 130 -143 207l-182 -119l-117 184l143 92l-149 93l108 182q174 -73 266 -135l209 137l115 -182l-145 -97q159 -157 226 -327.5t67 -388.5q0 -275 -152.5 -437.5t-415.5 -162.5q-259 0 -410 139t-151 379z M489 500q0 -242 164 -242q91 0 127.5 71t36.5 216q0 84 -45 136t-119 52q-92 0 -128 -56t-36 -177z" /> +<glyph unicode="&#xf1;" horiz-adv-x="1372" d="M135 0v1133h295l49 -140h23q50 80 138.5 120t203.5 40q188 0 292.5 -109t104.5 -307v-737h-391v618q0 113 -32.5 170.5t-104.5 57.5q-99 0 -143 -79t-44 -271v-496h-391zM274 1237q11 175 72 258.5t180 83.5q38 0 81 -15t87 -33t87 -33t81 -15q29 0 46 25t26 73h182 q-11 -167 -74 -254.5t-172 -87.5q-45 0 -90.5 15t-89.5 33t-85.5 33t-78.5 15q-54 0 -72 -98h-180z" /> +<glyph unicode="&#xf2;" horiz-adv-x="1305" d="M86 569q0 277 149.5 430.5t419.5 153.5q167 0 295 -71t197.5 -203.5t69.5 -309.5q0 -278 -149.5 -433.5t-418.5 -155.5q-258 0 -410.5 159t-152.5 430zM483 569q0 -146 39 -222.5t131 -76.5q91 0 128.5 76.5t37.5 222.5q0 145 -38 219t-130 74q-90 0 -129 -73.5 t-39 -219.5zM175 1548v21h430q52 -70 203 -233l59 -66v-29h-260q-69 44 -203.5 138.5t-228.5 168.5z" /> +<glyph unicode="&#xf3;" horiz-adv-x="1305" d="M86 569q0 277 149.5 430.5t419.5 153.5q167 0 295 -71t197.5 -203.5t69.5 -309.5q0 -278 -149.5 -433.5t-418.5 -155.5q-258 0 -410.5 159t-152.5 430zM483 569q0 -146 39 -222.5t131 -76.5q91 0 128.5 76.5t37.5 222.5q0 145 -38 219t-130 74q-90 0 -129 -73.5 t-39 -219.5zM416 1241v29q154 165 195.5 213t68.5 86h428v-21q-80 -64 -220 -163t-212 -144h-260z" /> +<glyph unicode="&#xf4;" horiz-adv-x="1305" d="M86 569q0 277 149.5 430.5t419.5 153.5q167 0 295 -71t197.5 -203.5t69.5 -309.5q0 -278 -149.5 -433.5t-418.5 -155.5q-258 0 -410.5 159t-152.5 430zM483 569q0 -146 39 -222.5t131 -76.5q91 0 128.5 76.5t37.5 222.5q0 145 -38 219t-130 74q-90 0 -129 -73.5 t-39 -219.5zM199 1241v29q69 65 144.5 153t113.5 146h393q94 -137 256 -299v-29h-254q-84 48 -201 150q-125 -107 -194 -150h-258z" /> +<glyph unicode="&#xf5;" horiz-adv-x="1305" d="M86 569q0 277 149.5 430.5t419.5 153.5q167 0 295 -71t197.5 -203.5t69.5 -309.5q0 -278 -149.5 -433.5t-418.5 -155.5q-258 0 -410.5 159t-152.5 430zM483 569q0 -146 39 -222.5t131 -76.5q91 0 128.5 76.5t37.5 222.5q0 145 -38 219t-130 74q-90 0 -129 -73.5 t-39 -219.5zM231 1237q11 175 72 258.5t180 83.5q38 0 81 -15t87 -33t87 -33t81 -15q29 0 46 25t26 73h182q-11 -167 -74 -254.5t-172 -87.5q-45 0 -90.5 15t-89.5 33t-85.5 33t-78.5 15q-54 0 -72 -98h-180z" /> +<glyph unicode="&#xf6;" horiz-adv-x="1305" d="M86 569q0 277 149.5 430.5t419.5 153.5q167 0 295 -71t197.5 -203.5t69.5 -309.5q0 -278 -149.5 -433.5t-418.5 -155.5q-258 0 -410.5 159t-152.5 430zM483 569q0 -146 39 -222.5t131 -76.5q91 0 128.5 76.5t37.5 222.5q0 145 -38 219t-130 74q-90 0 -129 -73.5 t-39 -219.5zM239 1413q0 75 46 116.5t124 41.5q79 0 125.5 -42.5t46.5 -115.5q0 -71 -46.5 -113.5t-125.5 -42.5q-78 0 -124 41t-46 115zM718 1413q0 75 46 116.5t126 41.5t126.5 -43t46.5 -115q0 -71 -46.5 -113.5t-126.5 -42.5q-81 0 -126.5 41.5t-45.5 114.5z" /> +<glyph unicode="&#xf7;" horiz-adv-x="1159" d="M72 588v268h1013v-268h-1013zM422 332q0 82 39.5 126t116.5 44q75 0 116 -43.5t41 -126.5q0 -80 -43.5 -125t-113.5 -45q-71 0 -113.5 44t-42.5 126zM422 1112q0 82 39.5 126t116.5 44q75 0 116 -43.5t41 -126.5q0 -80 -43.5 -125t-113.5 -45q-71 0 -113.5 44t-42.5 126z " /> +<glyph unicode="&#xf8;" horiz-adv-x="1362" d="M86 569q0 277 157 430.5t441 153.5q125 0 234 -39l71 111l168 -105l-67 -104q184 -158 184 -447q0 -280 -156.5 -434.5t-439.5 -154.5q-125 0 -229 34l-84 -131l-170 107l79 123q-188 158 -188 456zM461 569q0 -99 12 -147l289 448q-36 13 -82 13q-114 0 -166.5 -74 t-52.5 -240zM606 258q27 -8 76 -8q114 0 165.5 73t51.5 246q0 86 -10 131z" /> +<glyph unicode="&#xf9;" horiz-adv-x="1372" d="M133 395v738h391v-619q0 -111 31.5 -168t103.5 -57q101 0 144 79.5t43 268.5v496h391v-1133h-295l-49 141h-23q-49 -78 -136.5 -119.5t-205.5 -41.5q-187 0 -291 108.5t-104 306.5zM175 1548v21h430q52 -70 203 -233l59 -66v-29h-260q-69 44 -203.5 138.5t-228.5 168.5z " /> +<glyph unicode="&#xfa;" horiz-adv-x="1372" d="M133 395v738h391v-619q0 -111 31.5 -168t103.5 -57q101 0 144 79.5t43 268.5v496h391v-1133h-295l-49 141h-23q-49 -78 -136.5 -119.5t-205.5 -41.5q-187 0 -291 108.5t-104 306.5zM471 1241v29q154 165 195.5 213t68.5 86h428v-21q-80 -64 -220 -163t-212 -144h-260z " /> +<glyph unicode="&#xfb;" horiz-adv-x="1372" d="M133 395v738h391v-619q0 -111 31.5 -168t103.5 -57q101 0 144 79.5t43 268.5v496h391v-1133h-295l-49 141h-23q-49 -78 -136.5 -119.5t-205.5 -41.5q-187 0 -291 108.5t-104 306.5zM230 1241v29q69 65 144.5 153t113.5 146h393q94 -137 256 -299v-29h-254 q-84 48 -201 150q-125 -107 -194 -150h-258z" /> +<glyph unicode="&#xfc;" horiz-adv-x="1372" d="M133 395v738h391v-619q0 -111 31.5 -168t103.5 -57q101 0 144 79.5t43 268.5v496h391v-1133h-295l-49 141h-23q-49 -78 -136.5 -119.5t-205.5 -41.5q-187 0 -291 108.5t-104 306.5zM272 1413q0 75 46 116.5t124 41.5q79 0 125.5 -42.5t46.5 -115.5q0 -71 -46.5 -113.5 t-125.5 -42.5q-78 0 -124 41t-46 115zM751 1413q0 75 46 116.5t126 41.5t126.5 -43t46.5 -115q0 -71 -46.5 -113.5t-126.5 -42.5q-81 0 -126.5 41.5t-45.5 114.5z" /> +<glyph unicode="&#xfd;" horiz-adv-x="1249" d="M-2 1133h412l192 -650q14 -51 19 -123h8q8 69 24 121l197 652h399l-448 -1205q-86 -230 -211.5 -325t-327.5 -95q-78 0 -160 17v307q53 -12 121 -12q52 0 91 20t68 56.5t62 119.5zM401 1241v29q154 165 195.5 213t68.5 86h428v-21q-80 -64 -220 -163t-212 -144h-260z" /> +<glyph unicode="&#xfe;" horiz-adv-x="1317" d="M135 -492v2048h391v-344q0 -106 -18 -225h18q43 78 122 122t179 44q185 0 293.5 -154t108.5 -430q0 -271 -111.5 -430t-304.5 -159q-173 0 -287 129h-14l7 -60l7 -92v-449h-391zM526 571q0 -146 39 -211t123 -65q80 0 111.5 70.5t31.5 207.5q0 134 -33 203.5t-116 69.5 q-85 0 -119 -61.5t-37 -184.5v-29z" /> +<glyph unicode="&#xff;" horiz-adv-x="1249" d="M-2 1133h412l192 -650q14 -51 19 -123h8q8 69 24 121l197 652h399l-448 -1205q-86 -230 -211.5 -325t-327.5 -95q-78 0 -160 17v307q53 -12 121 -12q52 0 91 20t68 56.5t62 119.5zM216 1413q0 75 46 116.5t124 41.5q79 0 125.5 -42.5t46.5 -115.5q0 -71 -46.5 -113.5 t-125.5 -42.5q-78 0 -124 41t-46 115zM695 1413q0 75 46 116.5t126 41.5t126.5 -43t46.5 -115q0 -71 -46.5 -113.5t-126.5 -42.5q-81 0 -126.5 41.5t-45.5 114.5z" /> +<glyph unicode="&#x131;" horiz-adv-x="666" d="M137 0v1133h391v-1133h-391z" /> +<glyph unicode="&#x152;" horiz-adv-x="1960" d="M104 735q0 359 175 554.5t497 195.5q67 0 143.5 -7t106.5 -16h836v-317h-473v-230h436v-317h-436v-276h473v-322h-844q-34 -8 -110.5 -14t-133.5 -6q-319 0 -494.5 200t-175.5 555zM520 733q0 -205 64.5 -314.5t191.5 -109.5q141 0 217 43v760q-34 23 -93 36t-122 13 q-125 0 -191.5 -109.5t-66.5 -318.5z" /> +<glyph unicode="&#x153;" horiz-adv-x="2007" d="M86 569q0 277 149.5 430.5t419.5 153.5q226 0 375 -127q155 127 400 127q227 0 359 -136t132 -384v-172h-696q4 -90 74 -146.5t186 -56.5q194 0 364 86v-281q-92 -47 -187 -65t-228 -18q-238 0 -383 137q-151 -137 -402 -137q-258 0 -410.5 159t-152.5 430zM485 569 q0 -146 38 -222.5t130 -76.5q91 0 128.5 76.5t37.5 222.5q0 145 -38 219t-130 74q-89 0 -127.5 -74t-38.5 -219zM1231 707h340q-2 82 -48 131t-116 49q-162 0 -176 -180z" /> +<glyph unicode="&#x178;" horiz-adv-x="1360" d="M0 1462h430l250 -542l252 542h428l-481 -891v-571h-398v559zM268 1751q0 75 46 116.5t124 41.5q79 0 125.5 -42.5t46.5 -115.5q0 -71 -46.5 -113.5t-125.5 -42.5q-78 0 -124 41t-46 115zM747 1751q0 75 46 116.5t126 41.5t126.5 -43t46.5 -115q0 -71 -46.5 -113.5 t-126.5 -42.5q-81 0 -126.5 41.5t-45.5 114.5z" /> +<glyph unicode="&#x2c6;" horiz-adv-x="1237" d="M164 1241v29q69 65 144.5 153t113.5 146h393q94 -137 256 -299v-29h-254q-84 48 -201 150q-125 -107 -194 -150h-258z" /> +<glyph unicode="&#x2da;" horiz-adv-x="1120" d="M293 1489q0 116 71.5 185t192.5 69q118 0 195 -70t77 -182q0 -113 -76 -183.5t-196 -70.5q-121 0 -192.5 68.5t-71.5 183.5zM473 1489q0 -37 21 -60.5t63 -23.5q35 0 59.5 23.5t24.5 60.5q0 38 -24.5 61t-59.5 23t-59.5 -23t-24.5 -61z" /> +<glyph unicode="&#x2dc;" horiz-adv-x="1225" d="M176 1237q11 175 72 258.5t180 83.5q38 0 81 -15t87 -33t87 -33t81 -15q29 0 46 25t26 73h182q-11 -167 -74 -254.5t-172 -87.5q-45 0 -90.5 15t-89.5 33t-85.5 33t-78.5 15q-54 0 -72 -98h-180z" /> +<glyph unicode="&#x2000;" horiz-adv-x="959" /> +<glyph unicode="&#x2001;" horiz-adv-x="1919" /> +<glyph unicode="&#x2002;" horiz-adv-x="959" /> +<glyph unicode="&#x2003;" horiz-adv-x="1919" /> +<glyph unicode="&#x2004;" horiz-adv-x="639" /> +<glyph unicode="&#x2005;" horiz-adv-x="479" /> +<glyph unicode="&#x2006;" horiz-adv-x="319" /> +<glyph unicode="&#x2007;" horiz-adv-x="319" /> +<glyph unicode="&#x2008;" horiz-adv-x="239" /> +<glyph unicode="&#x2009;" horiz-adv-x="383" /> +<glyph unicode="&#x200a;" horiz-adv-x="106" /> +<glyph unicode="&#x2010;" horiz-adv-x="651" d="M43 393v312h565v-312h-565z" /> +<glyph unicode="&#x2011;" horiz-adv-x="651" d="M43 393v312h565v-312h-565z" /> +<glyph unicode="&#x2012;" horiz-adv-x="651" d="M43 393v312h565v-312h-565z" /> +<glyph unicode="&#x2013;" horiz-adv-x="1024" d="M74 414v276h876v-276h-876z" /> +<glyph unicode="&#x2014;" horiz-adv-x="2048" d="M74 414v276h1896v-276h-1896z" /> +<glyph unicode="&#x2018;" horiz-adv-x="512" d="M20 899q100 391 177 561h278q-67 -312 -98 -583h-342z" /> +<glyph unicode="&#x2019;" horiz-adv-x="512" d="M37 877q68 317 98 583h342l15 -22q-92 -366 -177 -561h-278z" /> +<glyph unicode="&#x201a;" horiz-adv-x="633" d="M57 -285q29 138 58.5 309.5t40.5 274.5h342l14 -23q-97 -381 -176 -561h-279z" /> +<glyph unicode="&#x201c;" horiz-adv-x="1022" d="M20 899q100 391 177 561h278q-67 -312 -98 -583h-342zM530 899q100 391 177 561h278q-67 -312 -98 -583h-342z" /> +<glyph unicode="&#x201d;" horiz-adv-x="1022" d="M37 877q68 317 98 583h342l15 -22q-92 -366 -177 -561h-278zM547 877q68 317 98 583h342l14 -22q-93 -371 -176 -561h-278z" /> +<glyph unicode="&#x201e;" horiz-adv-x="1143" d="M57 -285q29 138 58.5 309.5t40.5 274.5h342l14 -23q-97 -381 -176 -561h-279zM567 -285q29 138 58.5 309.5t40.5 274.5h342l14 -23q-97 -381 -176 -561h-279z" /> +<glyph unicode="&#x2022;" horiz-adv-x="803" d="M74 748q0 174 84.5 267t242.5 93t243 -94.5t85 -265.5q0 -172 -87 -266.5t-241 -94.5q-155 0 -241 93t-86 268zM668 1133z" /> +<glyph unicode="&#x2026;" horiz-adv-x="1776" d="M86 166q0 92 54.5 142t158.5 50q99 0 152 -50t53 -142q0 -90 -54.5 -140.5t-150.5 -50.5q-99 0 -156 50t-57 141zM678 166q0 92 54.5 142t158.5 50q99 0 152 -50t53 -142q0 -90 -54.5 -140.5t-150.5 -50.5q-99 0 -156 50t-57 141zM1270 166q0 92 54.5 142t158.5 50 q99 0 152 -50t53 -142q0 -90 -54.5 -140.5t-150.5 -50.5q-99 0 -156 50t-57 141z" /> +<glyph unicode="&#x202f;" horiz-adv-x="383" /> +<glyph unicode="&#x2039;" horiz-adv-x="819" d="M74 561v27l389 483l280 -149l-272 -347l272 -348l-280 -147z" /> +<glyph unicode="&#x203a;" horiz-adv-x="819" d="M76 227l272 348l-272 347l282 149l387 -483v-27l-387 -481z" /> +<glyph unicode="&#x2044;" horiz-adv-x="188" d="M-434 0l753 1462h302l-754 -1462h-301z" /> +<glyph unicode="&#x205f;" horiz-adv-x="479" /> +<glyph unicode="&#x2074;" horiz-adv-x="817" d="M29 725v188l350 555h295v-542h125v-201h-125v-139h-275v139h-370zM242 926h157v166q0 69 7 135q-40 -100 -62 -133z" /> +<glyph unicode="&#x20ac;" d="M55 467v205h129l-2 21v22l2 43h-129v205h148q51 255 212.5 387.5t413.5 132.5q180 0 349 -76l-119 -299q-120 51 -230 51q-112 0 -171.5 -53.5t-71.5 -142.5h338v-205h-353l-2 -29v-14l2 -44v1h287v-205h-264q33 -164 260 -164q145 0 266 55v-323q-102 -55 -291 -55 q-253 0 -412 126t-206 361h-156z" /> +<glyph unicode="&#x2122;" horiz-adv-x="1577" d="M37 1286v176h536v-176h-170v-545h-196v545h-170zM645 741v721h287l137 -479l150 479h276v-721h-195v400q0 68 7 110h-9l-151 -510h-164l-143 510h-9q7 -56 7 -110v-400h-193z" /> +<glyph unicode="&#xe000;" horiz-adv-x="1135" d="M0 1135h1135v-1135h-1135v1135z" /> +<glyph unicode="&#xfb01;" horiz-adv-x="1511" d="M973 1415q0 88 49 131t158 43t159 -44t50 -130q0 -172 -209 -172q-207 0 -207 172zM983 0v1133h391v-1133h-391zM45 840v192l158 96v19q0 224 91.5 322t293.5 98q78 0 147.5 -12t161.5 -42l-84 -253q-72 20 -141 20q-45 0 -65.5 -27.5t-20.5 -89.5v-30h241v-293h-241 v-840h-391v840h-150z" /> +<glyph unicode="&#xfb02;" horiz-adv-x="1507" d="M981 0v1556h391v-1556h-391zM45 840v192l158 96v19q0 224 91.5 322t293.5 98q78 0 147.5 -12t161.5 -42l-84 -253q-72 20 -141 20q-45 0 -65.5 -27.5t-20.5 -89.5v-30h241v-293h-241v-840h-391v840h-150z" /> +<glyph unicode="&#xfb03;" horiz-adv-x="2357" d="M45 840v192l158 96v19q0 224 91.5 322t293.5 98q78 0 147.5 -12t161.5 -42l-84 -253q-72 20 -141 20q-45 0 -65.5 -27.5t-20.5 -89.5v-30h241v-293h-241v-840h-391v840h-150zM891 840v192l158 96v19q0 224 91.5 322t293.5 98q78 0 147.5 -12t161.5 -42l-84 -253 q-72 20 -141 20q-45 0 -65.5 -27.5t-20.5 -89.5v-30h241v-293h-241v-840h-391v840h-150zM1819 1415q0 88 49 131t158 43t159 -44t50 -130q0 -172 -209 -172q-207 0 -207 172zM1829 0v1133h391v-1133h-391z" /> +<glyph unicode="&#xfb04;" horiz-adv-x="2353" d="M45 840v192l158 96v19q0 224 91.5 322t293.5 98q78 0 147.5 -12t161.5 -42l-84 -253q-72 20 -141 20q-45 0 -65.5 -27.5t-20.5 -89.5v-30h241v-293h-241v-840h-391v840h-150zM891 840v192l158 96v19q0 224 91.5 322t293.5 98q78 0 147.5 -12t161.5 -42l-84 -253 q-72 20 -141 20q-45 0 -65.5 -27.5t-20.5 -89.5v-30h241v-293h-241v-840h-391v840h-150zM1827 0v1556h391v-1556h-391z" /> +</font> +</defs></svg> +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBold-webfont.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.svg b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.svg @@ -0,0 +1,251 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata> +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom +</metadata> +<defs> +<font id="OpenSansExtraboldItalic" horiz-adv-x="1243" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="&#x09;" horiz-adv-x="532" /> +<glyph unicode="&#xa0;" horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="623" d="M12 127q0 107 65 170t179 63q87 0 133.5 -40.5t46.5 -114.5q0 -110 -63.5 -170t-173.5 -60q-88 0 -137.5 38.5t-49.5 113.5zM125 516l156 946h426l-254 -946h-328z" /> +<glyph unicode="&#x22;" horiz-adv-x="930" d="M182 934l72 528h342l-158 -528h-256zM623 934l73 528h342l-157 -528h-258z" /> +<glyph unicode="#" horiz-adv-x="1323" d="M14 393l21 238h266l57 200h-235l20 242h285l111 389h270l-111 -389h168l111 389h270l-110 -389h221l-21 -242h-270l-57 -200h243l-20 -238h-293l-111 -393h-270l113 393h-168l-113 -393h-270l112 393h-219zM571 631h168l58 200h-168z" /> +<glyph unicode="$" horiz-adv-x="1188" d="M61 162v311q126 -59 228 -86t203 -27q174 0 174 105q0 40 -32.5 72.5t-139.5 83.5q-139 62 -214 160t-75 227q0 176 133.5 288t357.5 127l29 133h168l-31 -137q161 -15 314 -90l-140 -270q-158 71 -295 71q-66 0 -103.5 -28t-37.5 -68q0 -53 39 -89.5t158 -94.5 q140 -68 205 -155.5t65 -213.5q0 -178 -133 -290t-361 -125l-38 -187h-168l41 191q-221 16 -347 92z" /> +<glyph unicode="%" horiz-adv-x="1878" d="M80 887q0 173 54 309.5t154.5 211.5t237.5 75q147 0 231.5 -85t84.5 -237q0 -165 -56.5 -303t-158 -215.5t-230.5 -77.5q-159 0 -238 83.5t-79 238.5zM252 0l1089 1462h289l-1081 -1462h-297zM371 891q0 -84 53 -84q52 0 89.5 110.5t37.5 239.5q0 43 -12 63.5t-41 20.5 q-50 0 -88.5 -110t-38.5 -240zM1057 301q0 173 54 309.5t154.5 211.5t237.5 75q147 0 231.5 -85t84.5 -237q0 -164 -56 -302t-158 -215.5t-231 -77.5q-159 0 -238 83t-79 238zM1348 305q0 -84 53 -84q52 0 89.5 110.5t37.5 239.5q0 44 -12 64t-41 20q-50 0 -88.5 -110 t-38.5 -240z" /> +<glyph unicode="&#x26;" horiz-adv-x="1501" d="M8 385q0 159 87.5 264.5t271.5 165.5q-37 46 -60.5 118.5t-23.5 131.5q0 197 126 308.5t355 111.5q189 0 302.5 -88t113.5 -236q0 -130 -80 -233t-262 -197l129 -186q36 36 75.5 114.5t63.5 161.5h383q-46 -161 -128.5 -305.5t-189.5 -253.5l191 -262h-442l-43 61 q-155 -81 -349 -81q-244 0 -382 106.5t-138 298.5zM399 424q0 -62 47.5 -99.5t124.5 -37.5t138 26l-193 279q-117 -52 -117 -168zM635 1092q0 -76 51 -144q72 31 106.5 79.5t34.5 107.5q0 35 -22 60.5t-60 25.5q-49 0 -79.5 -34.5t-30.5 -94.5z" /> +<glyph unicode="'" horiz-adv-x="487" d="M182 934l72 528h342l-158 -528h-256z" /> +<glyph unicode="(" horiz-adv-x="766" d="M68 326q0 330 124.5 619t387.5 558h323q-260 -281 -384 -576t-124 -618q0 -150 32.5 -326t84.5 -307h-293q-67 120 -109 299t-42 351zM720 1485z" /> +<glyph unicode=")" horiz-adv-x="766" d="M-133 -324q256 277 378 571.5t122 622.5q0 150 -32.5 322.5t-86.5 310.5h295q71 -124 111 -298t40 -351q0 -341 -123 -628t-378 -550h-326zM420 1485z" /> +<glyph unicode="*" horiz-adv-x="1110" d="M152 1108l100 278l319 -165l31 350l307 -62l-116 -331l368 30l-22 -301l-310 41l148 -311l-285 -86l-80 303l-166 -244l-249 185l254 229z" /> +<glyph unicode="+" horiz-adv-x="1159" d="M102 586v272h353v352h270v-352h352v-272h-352v-348h-270v348h-353z" /> +<glyph unicode="," horiz-adv-x="627" d="M-104 -264q53 121 147 387l41 115h348l8 -23q-116 -262 -256 -479h-288z" /> +<glyph unicode="-" horiz-adv-x="674" d="M23 393l63 312h553l-64 -312h-552z" /> +<glyph unicode="." horiz-adv-x="627" d="M0 127q0 109 65 171t179 62q84 0 132 -40t48 -115q0 -118 -60 -174t-190 -56q-78 0 -126 37t-48 115z" /> +<glyph unicode="/" horiz-adv-x="956" d="M-90 -20l838 1503h344l-838 -1503h-344z" /> +<glyph unicode="0" horiz-adv-x="1188" d="M63 465q0 295 85 533.5t235 362.5t348 124q135 0 230.5 -62.5t145.5 -174.5t50 -265q0 -298 -85 -529.5t-235 -352.5t-348 -121q-210 0 -318 126t-108 359zM453 457q0 -84 15 -123t60 -39q58 0 111.5 94.5t91 265.5t37.5 336q0 85 -18.5 131.5t-63.5 46.5 q-55 0 -110 -111t-89 -282t-34 -319z" /> +<glyph unicode="1" horiz-adv-x="1188" d="M150 1079l620 383h311l-307 -1462h-389l174 799q28 132 76 256q-78 -68 -131 -103l-203 -125z" /> +<glyph unicode="2" horiz-adv-x="1188" d="M-57 0l53 256l483 436q248 221 248 361q0 49 -26 73.5t-66 24.5q-120 0 -281 -147l-186 258q234 221 541 221q183 0 295 -99.5t112 -269.5q0 -152 -87 -285t-298 -315l-205 -176v-12h490l-68 -326h-1005z" /> +<glyph unicode="3" horiz-adv-x="1188" d="M14 59v332q167 -100 377 -100q138 0 206.5 46.5t68.5 133.5q0 54 -27 81t-86 39.5t-166 12.5h-84l53 291h78q147 0 229 46.5t82 127.5q0 46 -36 74t-99 28q-117 0 -270 -84l-158 248q126 81 243.5 114.5t258.5 33.5q201 0 321.5 -93t120.5 -253q0 -148 -89.5 -245 t-252.5 -130v-8q129 -25 202 -111.5t73 -212.5q0 -216 -178 -333t-482 -117q-116 0 -217.5 20.5t-167.5 58.5z" /> +<glyph unicode="4" horiz-adv-x="1188" d="M-10 283l51 256l762 923h360l-186 -884h149l-61 -295h-150l-59 -283h-377l60 283h-549zM391 578h209l49 194q29 107 60 211h-9q-51 -97 -114 -172z" /> +<glyph unicode="5" horiz-adv-x="1188" d="M20 63v324q79 -45 181 -70.5t184 -25.5q277 0 277 192q0 76 -50.5 123t-136.5 47q-53 0 -111 -10t-92 -22l-122 92l215 749h813l-68 -323h-471l-59 -185q35 4 75 4q181 0 293.5 -117.5t112.5 -316.5q0 -261 -161 -402.5t-466 -141.5q-129 0 -244.5 22t-169.5 61z" /> +<glyph unicode="6" horiz-adv-x="1188" d="M78 471q0 105 26 254q85 392 298.5 575t568.5 183q102 0 233 -31l-63 -303q-95 25 -183 25q-145 0 -237 -34t-151.5 -108.5t-106.5 -224.5h8q106 170 307 170q160 0 244 -103t84 -299q0 -175 -68.5 -311.5t-197 -210t-297.5 -73.5q-225 0 -345 124t-120 367zM463 420 q0 -66 26.5 -99.5t71.5 -33.5q66 0 109 76.5t43 181.5q0 129 -92 129q-68 0 -113 -73t-45 -181z" /> +<glyph unicode="7" horiz-adv-x="1188" d="M35 0l717 1135h-574l70 327h1030l-51 -231l-744 -1231h-448z" /> +<glyph unicode="8" horiz-adv-x="1188" d="M49 338q0 301 332 418q-156 121 -156 309q0 121 60.5 216.5t174 149.5t265.5 54q200 0 316 -92.5t116 -241.5q0 -128 -77.5 -228.5t-202.5 -140.5q92 -71 140 -158t48 -204q0 -206 -141 -323t-387 -117q-225 0 -356.5 99t-131.5 259zM414 385q0 -54 36.5 -88.5 t96.5 -34.5q70 0 112.5 42t42.5 110q0 115 -118 194q-170 -90 -170 -223zM588 1065q0 -38 23.5 -77t62.5 -58q58 22 92.5 71t34.5 103q0 49 -28.5 73.5t-65.5 24.5q-48 0 -83.5 -39.5t-35.5 -97.5z" /> +<glyph unicode="9" horiz-adv-x="1188" d="M106 10v314q92 -37 203 -37q187 0 291.5 87t144.5 281h-8q-59 -95 -132 -134.5t-169 -39.5q-151 0 -239 110t-88 296q0 176 65.5 310.5t190 210t297.5 75.5q230 0 352.5 -137.5t122.5 -393.5q0 -293 -103 -519.5t-285.5 -339.5t-431.5 -113q-115 0 -211 30zM502 932 q0 -144 92 -144q74 0 125 70.5t51 171.5q0 66 -27.5 106t-70.5 40q-73 0 -121.5 -71t-48.5 -173z" /> +<glyph unicode=":" horiz-adv-x="627" d="M0 127q0 109 65 171t179 62q84 0 132 -40t48 -115q0 -118 -60 -174t-190 -56q-78 0 -126 37t-48 115zM195 915q0 110 65 171t176 61q82 0 132 -37.5t50 -116.5q0 -119 -59 -175t-190 -56q-79 0 -126.5 37.5t-47.5 115.5z" /> +<glyph unicode=";" horiz-adv-x="627" d="M-117 -264q65 147 148 387l41 115h348l8 -23q-116 -262 -256 -479h-289zM195 915q0 110 65 171t176 61q82 0 132 -37.5t50 -116.5q0 -119 -59 -175t-190 -56q-79 0 -126.5 37.5t-47.5 115.5z" /> +<glyph unicode="&#x3c;" horiz-adv-x="1159" d="M88 627v172l973 508v-299l-576 -283l576 -252v-297z" /> +<glyph unicode="=" horiz-adv-x="1159" d="M102 399v271h975v-271h-975zM102 774v266h975v-266h-975z" /> +<glyph unicode="&#x3e;" horiz-adv-x="1159" d="M109 176v297l575 252l-575 283v299l972 -508v-172z" /> +<glyph unicode="?" horiz-adv-x="999" d="M162 1348q231 135 461 135q201 0 319.5 -90t118.5 -248q0 -89 -27.5 -156t-79 -120.5t-170.5 -125.5q-100 -60 -142.5 -100t-55.5 -84l-15 -43h-315l12 64q15 80 42 138t71 104t141 110q89 58 125.5 95t36.5 77q0 70 -90 70q-126 0 -313 -109zM176 127q0 107 65 170 t179 63q87 0 133.5 -40.5t46.5 -114.5q0 -110 -63.5 -170t-174.5 -60q-87 0 -136.5 39t-49.5 113z" /> +<glyph unicode="@" horiz-adv-x="1837" d="M82 500q0 288 117 511t335.5 347.5t485.5 124.5q355 0 554.5 -174t199.5 -482q0 -170 -69.5 -314t-191 -225t-266.5 -81q-170 0 -219 129h-10q-48 -65 -111.5 -97t-156.5 -32q-117 0 -191 83.5t-74 221.5q0 156 74 294.5t196.5 211t276.5 72.5q155 0 336 -70l-100 -414 q-23 -94 -23 -137q0 -41 39 -41q64 0 116 48.5t81.5 138.5t29.5 206q0 213 -133.5 322.5t-382.5 109.5q-187 0 -336.5 -91.5t-232 -258t-82.5 -379.5q0 -145 55 -254t153.5 -168t223.5 -59q103 0 234 24.5t245 69.5v-225q-90 -43 -223.5 -70.5t-251.5 -27.5 q-209 0 -367.5 83.5t-244.5 240t-86 362.5zM764 532q0 -104 78 -104q61 0 99.5 51.5t74.5 188.5l47 190q-23 10 -51 10q-73 0 -128.5 -47.5t-87.5 -127t-32 -161.5z" /> +<glyph unicode="A" horiz-adv-x="1384" d="M-121 0l744 1462h503l123 -1462h-381l-10 274h-448l-125 -274h-406zM553 586h293l-17 424l-2 86q0 75 4 131q-24 -86 -61 -166z" /> +<glyph unicode="B" horiz-adv-x="1298" d="M33 0l309 1462h487q217 0 329 -82.5t112 -236.5q0 -288 -297 -377v-8q88 -29 140 -101.5t52 -177.5q0 -229 -152.5 -354t-432.5 -125h-547zM489 305h82q86 0 143.5 48.5t57.5 121.5q0 69 -33 103t-116 34h-68zM614 901h72q88 0 133 38t45 122q0 102 -127 102h-63z" /> +<glyph unicode="C" horiz-adv-x="1290" d="M104 549q0 266 101.5 488t276 335t399.5 113q265 0 481 -131l-148 -305q-93 55 -171 82.5t-162 27.5q-108 0 -195 -78t-136.5 -215t-49.5 -297q0 -134 56 -200t161 -66q83 0 168 20.5t200 69.5v-323q-203 -90 -440 -90q-260 0 -400.5 148.5t-140.5 420.5z" /> +<glyph unicode="D" horiz-adv-x="1401" d="M33 0l309 1462h416q276 0 427.5 -144.5t151.5 -408.5q0 -280 -99 -485.5t-287.5 -314.5t-446.5 -109h-471zM494 324h69q110 0 196.5 70t134.5 199.5t48 295.5q0 125 -54 189.5t-151 64.5h-71z" /> +<glyph unicode="E" horiz-adv-x="1151" d="M33 0l309 1462h868l-65 -317h-477l-47 -230h444l-72 -317h-444l-57 -276h477l-68 -322h-868z" /> +<glyph unicode="F" horiz-adv-x="1165" d="M33 0l309 1462h862l-67 -317h-471l-58 -279h436l-69 -319h-438l-113 -547h-391z" /> +<glyph unicode="G" horiz-adv-x="1430" d="M104 563q0 267 110 482t301.5 327.5t445.5 112.5q266 0 448 -107l-147 -309q-153 90 -306 90q-132 0 -233.5 -72.5t-162 -214.5t-60.5 -303q0 -264 209 -264q63 0 133 14l51 232h-229l67 305h610l-167 -795q-250 -81 -521 -81q-261 0 -405 152t-144 431z" /> +<glyph unicode="H" horiz-adv-x="1462" d="M33 0l309 1462h391l-112 -542h348l112 542h392l-310 -1462h-391l125 596h-346l-127 -596h-391z" /> +<glyph unicode="I" horiz-adv-x="727" d="M31 0l309 1462h397l-309 -1462h-397z" /> +<glyph unicode="J" horiz-adv-x="764" d="M-328 -113q99 -24 174 -24q107 0 162 59t84 195l289 1345h391l-299 -1394q-43 -200 -113 -312.5t-182.5 -164.5t-292.5 -52q-106 0 -213 29v319z" /> +<glyph unicode="K" horiz-adv-x="1370" d="M33 0l309 1462h391l-135 -624l38 59q88 143 130 195l297 370h459l-551 -674l270 -788h-438l-174 578l-97 -56l-108 -522h-391z" /> +<glyph unicode="L" horiz-adv-x="1079" d="M33 0l309 1462h391l-241 -1143h477l-68 -319h-868z" /> +<glyph unicode="M" horiz-adv-x="1862" d="M33 0l309 1462h518v-1038h8l478 1038h526l-313 -1462h-351l117 549q50 228 108 436l15 64h-8l-482 -1049h-370v1049h-8q-67 -417 -86 -512l-113 -537h-348z" /> +<glyph unicode="N" horiz-adv-x="1618" d="M33 0l309 1462h455l286 -983h9q29 236 57 371l131 612h348l-309 -1462h-455l-289 1028h-8q-29 -291 -57 -418l-129 -610h-348z" /> +<glyph unicode="O" horiz-adv-x="1509" d="M104 543q0 265 103 487t280.5 338.5t409.5 116.5q260 0 404.5 -148.5t144.5 -414.5t-99.5 -486.5t-274.5 -338t-406 -117.5q-269 0 -415.5 149t-146.5 414zM500 545q0 -242 200 -242q95 0 176.5 83t128 224t46.5 308q0 114 -48 178.5t-139 64.5q-99 0 -182 -84 t-132.5 -231t-49.5 -301z" /> +<glyph unicode="P" horiz-adv-x="1276" d="M33 0l309 1462h373q259 0 397.5 -113.5t138.5 -324.5q0 -252 -171.5 -395.5t-469.5 -143.5h-86l-100 -485h-391zM594 805h63q91 0 147 58.5t56 148.5q0 59 -36 95t-99 36h-59z" /> +<glyph unicode="Q" horiz-adv-x="1509" d="M104 543q0 265 102.5 486t282 338.5t414.5 117.5q258 0 400.5 -149.5t142.5 -413.5q0 -280 -114 -509t-310 -339l238 -422h-439l-162 328h-12q-258 0 -400.5 149.5t-142.5 413.5zM500 539q0 -115 47.5 -172.5t134.5 -57.5q102 0 186.5 81t133.5 224.5t49 311.5 q0 114 -47 172.5t-134 58.5q-103 0 -188.5 -83t-133.5 -226t-48 -309z" /> +<glyph unicode="R" horiz-adv-x="1331" d="M33 0l309 1462h387q252 0 386 -100t134 -301q0 -156 -71 -272t-211 -177l224 -516l40 -96h-426l-195 532h-73l-113 -532h-391zM600 829h51q95 0 151 54.5t56 152.5q0 62 -34.5 94.5t-100.5 32.5h-53z" /> +<glyph unicode="S" horiz-adv-x="1122" d="M43 76v350q84 -53 192.5 -89t196.5 -36q74 0 112 31t38 88q0 27 -12 50.5t-34 47t-118 103.5q-117 94 -170 192t-53 215q0 131 65.5 235.5t185 162t267.5 57.5q239 0 430 -107l-135 -297q-171 88 -291 88q-64 0 -98.5 -28t-34.5 -82q0 -49 33.5 -91.5t127.5 -113.5 q118 -87 175 -183t57 -220q0 -222 -147 -345.5t-410 -123.5q-110 0 -208 24.5t-169 71.5z" /> +<glyph unicode="T" horiz-adv-x="1130" d="M156 1139l69 323h1028l-71 -323h-318l-237 -1139h-391l237 1139h-317z" /> +<glyph unicode="U" horiz-adv-x="1436" d="M125 410q0 64 12 129l199 923h391l-195 -913q-14 -68 -14 -115q0 -127 121 -127q94 0 147.5 64.5t81.5 197.5l191 893h391l-199 -932q-59 -281 -225 -415.5t-451 -134.5q-134 0 -236.5 55t-158 154t-55.5 221z" /> +<glyph unicode="V" horiz-adv-x="1264" d="M150 1462h382l27 -801v-51q0 -144 -16 -256h8q14 64 44.5 157.5t55.5 145.5l350 805h414l-725 -1462h-436z" /> +<glyph unicode="W" horiz-adv-x="1915" d="M152 1462h370l-10 -733q-6 -267 -25 -375l40 104l94 232l335 772h336v-792q0 -156 -26 -316q10 28 133 346l303 762h387l-635 -1462h-461v620q0 155 13 324q-33 -133 -118 -349l-253 -595h-434z" /> +<glyph unicode="X" horiz-adv-x="1358" d="M-125 0l563 776l-223 686h416l123 -469l309 469h448l-538 -725l262 -737h-432l-146 498l-338 -498h-444z" /> +<glyph unicode="Y" horiz-adv-x="1237" d="M164 1462h403l90 -542l312 542h436l-612 -895l-121 -567h-391l120 567z" /> +<glyph unicode="Z" horiz-adv-x="1104" d="M-92 0l47 242l690 901h-479l67 319h986l-52 -245l-700 -898h543l-68 -319h-1034z" /> +<glyph unicode="[" horiz-adv-x="737" d="M-53 -344l393 1847h530l-55 -254h-215l-285 -1339h215l-53 -254h-530zM182 -324zM491 1485z" /> +<glyph unicode="\" horiz-adv-x="956" d="M221 1483h309l248 -1503h-319z" /> +<glyph unicode="]" horiz-adv-x="737" d="M-133 -344l53 254h213l285 1339h-215l55 254h528l-393 -1847h-526zM65 -324zM533 1485z" /> +<glyph unicode="^" horiz-adv-x="1096" d="M-6 502l631 960h172l284 -960h-274l-156 569l-360 -569h-297z" /> +<glyph unicode="_" horiz-adv-x="922" d="M-184 -379l57 246h930l-58 -246h-929z" /> +<glyph unicode="`" horiz-adv-x="1135" d="M485 1548v21h396q29 -157 94 -303v-25h-236q-82 75 -152 159t-102 148z" /> +<glyph unicode="a" d="M84 412q0 179 73 365t184.5 281t246.5 95q84 0 148 -37.5t114 -122.5h8l53 140h310l-240 -1133h-309l10 123h-8q-56 -78 -121 -110.5t-147 -32.5q-158 0 -240 111.5t-82 320.5zM479 434q0 -143 86 -143q50 0 95.5 58.5t72.5 156.5t27 192q0 65 -20 104.5t-62 39.5 q-76 0 -137.5 -126.5t-61.5 -281.5z" /> +<glyph unicode="b" d="M23 0l329 1556h387l-49 -231q-38 -175 -90 -301h8q48 59 77.5 81.5t66.5 35t86 12.5q155 0 238 -111.5t83 -320.5q0 -178 -70.5 -362t-182.5 -281.5t-249 -97.5q-83 0 -145 32t-125 113h-8l-49 -125h-307zM485 434q0 -65 19 -104t59 -39q49 0 96 59t76 156t29 192 q0 144 -86 144q-50 0 -95 -57t-71.5 -154t-26.5 -197z" /> +<glyph unicode="c" horiz-adv-x="1032" d="M84 442q0 201 76.5 364.5t215 255t314.5 91.5q195 0 367 -80l-123 -287q-133 60 -225 60q-62 0 -115 -48t-87 -143.5t-34 -187.5q0 -91 30 -133.5t95 -42.5q72 0 139.5 23t143.5 63v-307q-80 -44 -168.5 -67t-206.5 -23q-199 0 -310.5 120.5t-111.5 341.5z" /> +<glyph unicode="d" horiz-adv-x="1237" d="M84 412q0 178 71.5 363t183.5 281.5t247 96.5q75 0 126 -30.5t111 -121.5h8l2 37q7 138 25 217l62 301h391l-330 -1556h-309l10 123h-8q-57 -79 -120 -111t-148 -32q-158 0 -240 111.5t-82 320.5zM479 434q0 -143 86 -143q50 0 95.5 58.5t72.5 156.5t27 192 q0 144 -80 144q-49 0 -96 -59t-76 -155.5t-29 -193.5z" /> +<glyph unicode="e" horiz-adv-x="1186" d="M84 428q0 211 83.5 380.5t229 257t336.5 87.5q190 0 299 -86t109 -229q0 -201 -156.5 -308.5t-452.5 -107.5h-59v-16q0 -148 164 -148q79 0 155 23.5t173 74.5v-274q-112 -57 -209 -79.5t-224 -22.5q-212 0 -330 118.5t-118 329.5zM512 664h29q109 0 171 41.5t62 109.5 q0 32 -20 54t-64 22q-61 0 -114 -69.5t-64 -157.5z" /> +<glyph unicode="f" horiz-adv-x="840" d="M-209 -162q63 -18 117 -18q74 0 112 30t52 95l190 897h-166l43 190l189 96l16 74q43 192 146.5 278.5t275.5 86.5q80 0 155 -16t128 -42l-99 -264q-64 31 -129 31q-35 0 -59.5 -18.5t-32.5 -53.5l-16 -71h211l-66 -291h-209l-205 -959q-43 -192 -153.5 -283.5 t-292.5 -91.5q-110 0 -207 27v303z" /> +<glyph unicode="g" horiz-adv-x="1145" d="M-133 -207q0 98 68 169t212 118q-37 23 -60.5 60t-23.5 79q0 71 51 126t152 101q-131 103 -131 281q0 196 136 311t368 115q51 0 107.5 -6t89.5 -14h399l-41 -207l-160 -52q10 -40 10 -94q0 -191 -130 -308.5t-339 -117.5q-76 0 -124 13q-20 -11 -34 -22t-14 -30 q0 -43 111 -59l137 -18q174 -25 250 -91.5t76 -189.5q0 -215 -168.5 -332t-478.5 -117q-212 0 -337.5 75.5t-125.5 209.5zM197 -152q0 -86 170 -86q125 0 190.5 29t65.5 82q0 36 -33 54.5t-115 27.5l-115 12q-78 -11 -120.5 -41.5t-42.5 -77.5zM500 692q0 -94 67 -94 q52 0 85.5 68.5t33.5 158.5q0 95 -61 95q-38 0 -66 -33.5t-43.5 -87.5t-15.5 -107z" /> +<glyph unicode="h" horiz-adv-x="1274" d="M23 0l329 1556h387l-53 -249q-35 -158 -88 -283h8q101 129 273 129q141 0 220 -85.5t79 -236.5q0 -106 -25 -229l-127 -602h-387l129 618q18 78 18 142q0 43 -22 64.5t-53 21.5q-125 0 -185 -293l-116 -553h-387z" /> +<glyph unicode="i" horiz-adv-x="666" d="M23 0l239 1133h389l-241 -1133h-387zM309 1382q0 103 59.5 156t166.5 53q91 0 140.5 -36.5t49.5 -104.5q0 -100 -58 -154.5t-167 -54.5q-191 0 -191 141z" /> +<glyph unicode="j" horiz-adv-x="666" d="M-264 -162q56 -18 112 -18q142 0 175 147l247 1166h387l-260 -1227q-40 -193 -157 -295.5t-297 -102.5q-110 0 -207 27v303zM317 1382q0 103 59.5 156t166.5 53q91 0 140.5 -36.5t49.5 -104.5q0 -94 -55 -151.5t-170 -57.5q-191 0 -191 141z" /> +<glyph unicode="k" horiz-adv-x="1264" d="M23 0l325 1556h387l-139 -663q-17 -77 -68 -223h9q84 127 153 200l242 263h442l-491 -512l274 -621h-438l-139 391l-101 -53l-69 -338h-387z" /> +<glyph unicode="l" horiz-adv-x="666" d="M23 0l329 1556h387l-329 -1556h-387z" /> +<glyph unicode="m" horiz-adv-x="1896" d="M23 0l239 1133h309l-16 -187h8q61 114 137 160.5t191 46.5q117 0 180.5 -53.5t89.5 -153.5h8q65 106 149 156.5t195 50.5q141 0 214 -84.5t73 -249.5q0 -97 -22 -205l-125 -614h-387l129 631q14 56 14 133q0 40 -19 61t-51 21q-74 0 -119.5 -76t-76.5 -227l-111 -543 h-387l131 631q15 90 15 121q0 94 -72 94q-68 0 -113.5 -74.5t-77.5 -220.5l-118 -551h-387z" /> +<glyph unicode="n" horiz-adv-x="1274" d="M23 0l239 1133h309l-12 -158h8q55 95 129.5 136.5t182.5 41.5q141 0 220 -85.5t79 -236.5q0 -106 -25 -229l-127 -602h-387l129 618q18 78 18 142q0 43 -22 64.5t-53 21.5q-57 0 -105.5 -71t-79.5 -222l-116 -553h-387z" /> +<glyph unicode="o" d="M84 416q0 210 79.5 379.5t223.5 263.5t336 94q209 0 322.5 -113t113.5 -323t-79.5 -379.5t-223.5 -263.5t-336 -94q-209 0 -322.5 113t-113.5 323zM479 403q0 -133 84 -133q81 0 141 139t60 320q0 66 -23 99.5t-63 33.5q-82 0 -140.5 -139.5t-58.5 -319.5z" /> +<glyph unicode="p" d="M-82 -492l344 1625h309l-12 -127h8q96 147 258 147q156 0 245 -111.5t89 -306.5q0 -203 -70 -382.5t-185.5 -276t-252.5 -96.5q-143 0 -231 145h-8q-12 -166 -56 -371l-51 -246h-387zM485 434q0 -65 23 -104t65 -39q48 0 92 57t71.5 153t27.5 197q0 144 -86 144 q-50 0 -95 -57t-71.5 -154t-26.5 -197z" /> +<glyph unicode="q" d="M84 408q0 181 71.5 366.5t183 282t247.5 96.5q89 0 145.5 -33t118.5 -127h8l53 140h310l-344 -1625h-392l68 293q25 116 90 310h-8q-55 -74 -114 -102.5t-134 -28.5q-89 0 -158 50.5t-107 148t-38 229.5zM479 434q0 -143 86 -143q50 0 95.5 58.5t72.5 156.5t27 192 q0 144 -80 144q-49 0 -96 -59t-76 -155.5t-29 -193.5z" /> +<glyph unicode="r" horiz-adv-x="895" d="M23 0l239 1133h309l-18 -189h8q65 112 141 160.5t199 48.5q56 0 80 -8l-84 -383q-54 22 -123 22q-103 0 -164.5 -70.5t-93.5 -215.5l-106 -498h-387z" /> +<glyph unicode="s" horiz-adv-x="1028" d="M31 43v311q92 -50 171 -70t160 -20q68 0 102 18.5t34 51.5q0 35 -26 60.5t-130 84.5q-106 58 -154.5 133t-48.5 183q0 172 121 265t344 93q112 0 204 -26t179 -80l-121 -252q-66 43 -136.5 68.5t-121.5 25.5q-76 0 -76 -68q0 -29 31.5 -51t102.5 -57q225 -112 225 -320 q0 -199 -130 -306t-374 -107q-222 0 -356 63z" /> +<glyph unicode="t" horiz-adv-x="936" d="M63 842l41 190l218 88l137 240h258l-49 -227h288l-63 -291h-289l-84 -383q-16 -77 -16 -105q0 -63 63 -63q66 0 183 47v-291q-136 -67 -340 -67q-148 0 -224.5 63.5t-76.5 208.5q0 76 24 188l84 402h-154z" /> +<glyph unicode="u" horiz-adv-x="1274" d="M96 301q0 106 25 229l127 603h387l-129 -617q-19 -82 -19 -141q0 -44 22.5 -65t53.5 -21q59 0 107.5 78.5t77.5 214.5l116 551h387l-239 -1133h-310l13 158h-8q-54 -93 -128.5 -135.5t-183.5 -42.5q-141 0 -220 85.5t-79 235.5z" /> +<glyph unicode="v" horiz-adv-x="1114" d="M88 1133h385l27 -603q0 -73 -8 -118h8q1 14 18 63t36 90t265 568h414l-612 -1133h-388z" /> +<glyph unicode="w" horiz-adv-x="1686" d="M102 1133h365v-512q0 -182 -8 -259h8q46 177 88 295l172 476h428l-20 -476q-9 -129 -33 -295h8q7 22 15.5 47.5t48.5 140t241 583.5h385l-538 -1133h-422l20 449q2 73 11.5 209t21.5 219h-8q-60 -233 -121 -390l-189 -487h-407z" /> +<glyph unicode="x" horiz-adv-x="1159" d="M-119 0l473 578l-207 555h422l76 -314l186 314h459l-465 -576l228 -557h-428l-80 328l-211 -328h-453z" /> +<glyph unicode="y" horiz-adv-x="1114" d="M-129 -168q46 -12 109 -12q87 0 142.5 36.5t98.5 114.5l23 41l-162 1121h389l43 -562l2 -62v-87h8q37 132 50 165.5t239 545.5h416l-670 -1276q-96 -185 -223 -267t-311 -82q-92 0 -154 17v307z" /> +<glyph unicode="z" horiz-adv-x="993" d="M-41 0l43 221l502 613h-348l67 299h811l-53 -242l-496 -592h383l-65 -299h-844z" /> +<glyph unicode="{" horiz-adv-x="735" d="M-16 434l53 287q119 0 175 38.5t77 133.5l55 246q28 124 76.5 190t130 99.5t203.5 33.5h129l-62 -280q-81 -2 -120 -29.5t-56 -99.5l-53 -258q-20 -96 -85.5 -151.5t-193.5 -70.5v-8q90 -29 130 -87t40 -146q0 -17 -10 -74l-35 -164q-6 -30 -6 -49q0 -88 113 -88v-281 h-82q-183 0 -272 68.5t-89 208.5q0 63 15 127l37 174q6 24 6 43q0 75 -42 106t-134 31z" /> +<glyph unicode="|" horiz-adv-x="1159" d="M442 -465v2013h271v-2013h-271z" /> +<glyph unicode="}" horiz-adv-x="735" d="M-123 -43q73 3 109 13.5t54 33.5t30 82l53 258q21 99 88 154t190 67v8q-170 55 -170 234q0 12 11 74l34 163q7 29 7 50q0 88 -136 88l54 280h61q168 0 259 -70.5t91 -203.5q0 -69 -14 -129l-37 -174q-6 -26 -6 -43q0 -66 44.5 -100.5t148.5 -34.5l-58 -287 q-121 0 -182.5 -40.5t-81.5 -133.5l-55 -246q-37 -171 -137.5 -247.5t-282.5 -76.5h-74v281z" /> +<glyph unicode="~" horiz-adv-x="1159" d="M96 524v285q107 109 262 109q61 0 110.5 -11.5t152.5 -52.5q67 -28 114 -41.5t99 -13.5q51 0 115.5 32t121.5 89v-285q-107 -109 -262 -109q-62 0 -113.5 12.5t-148.5 51.5q-75 31 -118.5 43t-92.5 12q-52 0 -114.5 -30t-125.5 -91z" /> +<glyph unicode="&#xa1;" horiz-adv-x="623" d="M-109 -338l254 946h328l-156 -946h-426zM107 -324zM162 924q0 109 64 169t173 60q89 0 138 -39.5t49 -112.5q0 -107 -65 -170t-179 -63q-87 0 -133.5 40.5t-46.5 115.5z" /> +<glyph unicode="&#xa2;" horiz-adv-x="1188" d="M154 586q0 306 140.5 510t371.5 239l32 148h230l-33 -150q122 -19 231 -76l-122 -286q-79 37 -128 48t-98 11q-63 0 -115 -49.5t-84 -146.5t-32 -207q0 -79 31 -113.5t90 -34.5q72 0 140 25t142 65v-311q-145 -78 -307 -90l-41 -188h-229l51 208q-270 74 -270 398z" /> +<glyph unicode="&#xa3;" horiz-adv-x="1188" d="M-18 0l63 313q76 21 120.5 49t69 69.5t41.5 123.5l21 96h-188l57 279h188l23 129q26 149 85 243t150.5 137.5t237.5 43.5q89 0 177 -19t196 -67l-144 -299q-66 31 -114 47t-99 16q-35 0 -56.5 -24.5t-35.5 -92.5l-24 -114h251l-57 -279h-252l-20 -94 q-16 -74 -69.5 -133.5t-133.5 -93.5h604l-72 -330h-1019z" /> +<glyph unicode="&#xa4;" horiz-adv-x="1188" d="M106 1032l185 185l127 -125q96 43 182 43q96 0 184 -48l125 130l189 -179l-129 -129q43 -82 43 -186q0 -94 -43 -186l123 -123l-183 -183l-125 123q-96 -41 -184 -41q-108 0 -186 39l-123 -119l-182 183l127 123q-46 90 -46 184q0 92 46 184zM451 723q0 -64 43 -108 t106 -44q65 0 110.5 44.5t45.5 107.5q0 61 -44.5 106t-111.5 45q-64 0 -106.5 -44t-42.5 -107z" /> +<glyph unicode="&#xa5;" horiz-adv-x="1188" d="M76 190l43 205h227l25 129h-226l45 205h179l-187 733h385l72 -487l293 487h393l-489 -733h184l-45 -205h-223l-27 -129h223l-43 -205h-223l-41 -190h-379l41 190h-227z" /> +<glyph unicode="&#xa6;" horiz-adv-x="1159" d="M444 395h271v-839h-271v839zM444 705v841h271v-841h-271z" /> +<glyph unicode="&#xa7;" horiz-adv-x="1036" d="M37 70v249q85 -52 173 -86t185 -34q69 0 109.5 28.5t40.5 75.5q0 38 -31 70.5t-104 72.5q-130 71 -191 152t-61 178q0 84 46 156t132 125q-38 38 -59 89.5t-21 102.5q0 160 116 244t339 84q184 0 360 -102l-100 -224q-91 58 -159.5 79.5t-133.5 21.5q-60 0 -85.5 -22.5 t-25.5 -51.5q0 -33 14 -53.5t46.5 -43t89.5 -48.5q244 -113 244 -312q0 -99 -38 -171t-130 -124q32 -38 50.5 -90.5t18.5 -109.5q0 -170 -127 -260.5t-358 -90.5q-110 0 -197 25.5t-143 69.5zM442 817q0 -43 37 -84t125 -90q74 51 74 127q0 54 -36.5 95t-117.5 75 q-37 -19 -59.5 -54t-22.5 -69z" /> +<glyph unicode="&#xa8;" horiz-adv-x="1135" d="M336 1384q0 187 201 187q170 0 170 -125q0 -189 -201 -189q-88 0 -129 31t-41 96zM823 1384q0 187 201 187q168 0 168 -125q0 -97 -49.5 -143t-149.5 -46q-88 0 -129 31t-41 96z" /> +<glyph unicode="&#xa9;" horiz-adv-x="1688" d="M113 731q0 202 101.5 378t275.5 275t374 99t375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-206 0 -380 102.5t-272.5 276.5t-98.5 372zM276 731q0 -158 78.5 -294t215 -215t294.5 -79q157 0 293 77.5t215.5 214t79.5 296.5q0 158 -78.5 294.5 t-215 215t-294.5 78.5t-295.5 -79.5t-215 -215.5t-77.5 -293zM461 735q0 220 113.5 341.5t320.5 121.5q166 0 332 -82l-92 -205q-114 60 -222 60q-80 0 -126 -61t-46 -179q0 -128 44 -185t135 -57q138 0 258 68v-231q-126 -64 -273 -64q-213 0 -328.5 125t-115.5 348z" /> +<glyph unicode="&#xaa;" horiz-adv-x="827" d="M139 1001q0 120 45 232t123 177t176 65q64 0 111.5 -20t101.5 -79h9l36 86h199l-170 -721h-195l9 86h-9q-89 -98 -223 -98q-60 0 -108 31.5t-76.5 91.5t-28.5 149zM412 1012q0 -48 19 -74.5t50 -26.5q46 0 79 38.5t51 100t18 128.5q0 53 -19.5 83.5t-52.5 30.5 q-39 0 -72.5 -40.5t-53 -107.5t-19.5 -132z" /> +<glyph unicode="&#xab;" horiz-adv-x="1276" d="M61 553v10l408 518l264 -204l-266 -334l111 -330l-334 -137zM608 582v10l424 495l260 -210l-278 -306l123 -358l-334 -137z" /> +<glyph unicode="&#xac;" horiz-adv-x="1159" d="M82 586v272h975v-620h-271v348h-704z" /> +<glyph unicode="&#xad;" horiz-adv-x="674" d="M23 393l63 312h553l-64 -312h-552z" /> +<glyph unicode="&#xae;" horiz-adv-x="1688" d="M113 731q0 202 101.5 378t275.5 275t374 99t375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-206 0 -380 102.5t-272.5 276.5t-98.5 372zM276 731q0 -158 78.5 -294t215 -215t294.5 -79q157 0 293 77.5t215.5 214t79.5 296.5q0 158 -78.5 294.5 t-215 215t-294.5 78.5t-295.5 -79.5t-215 -215.5t-77.5 -293zM535 313v875h290q214 0 317 -70.5t103 -199.5q0 -91 -44.5 -153t-139.5 -97l211 -355h-285l-160 320h-12v-320h-280zM815 809h10q78 0 108 22t30 76t-35.5 70t-104.5 16h-8v-184z" /> +<glyph unicode="&#xaf;" horiz-adv-x="922" d="M183 1554l57 246h930l-58 -246h-929z" /> +<glyph unicode="&#xb0;" horiz-adv-x="864" d="M166 1114q0 97 49 182.5t135 136t185 50.5q98 0 184 -50t135 -136.5t49 -182.5q0 -98 -49.5 -183t-135.5 -133t-183 -48q-99 0 -185 49t-135 133t-49 182zM403 1114q0 -51 39.5 -89t92.5 -38q52 0 91.5 38t39.5 89q0 53 -38.5 93t-92.5 40q-55 0 -93.5 -39.5t-38.5 -93.5 z" /> +<glyph unicode="&#xb1;" horiz-adv-x="1159" d="M102 0v270h975v-270h-975zM102 694v271h353v352h270v-352h352v-271h-352v-350h-270v350h-353z" /> +<glyph unicode="&#xb2;" horiz-adv-x="848" d="M23 584l43 204l276 211q108 83 144 124t36 75q0 51 -63 51q-35 0 -85 -18t-104 -62l-118 191q84 65 172.5 94t216.5 29q134 0 218.5 -61t84.5 -156q0 -70 -31.5 -129.5t-102 -121t-251.5 -175.5h319l-51 -256h-704z" /> +<glyph unicode="&#xb3;" horiz-adv-x="848" d="M66 639v225q63 -43 131.5 -62.5t124.5 -19.5q151 0 151 80q0 68 -113 68h-120l43 194h96q71 0 114.5 21.5t43.5 66.5q0 28 -22 43t-54 15q-79 0 -185 -66l-100 182q83 52 161 73.5t181 21.5q137 0 220 -57t83 -152q0 -91 -55.5 -146t-175.5 -84v-8q92 -23 129 -69.5 t37 -112.5q0 -127 -104 -205t-275 -78q-106 0 -177.5 16t-133.5 54z" /> +<glyph unicode="&#xb4;" horiz-adv-x="1135" d="M453 1241v23q123 102 282 305h439v-15q-45 -54 -191.5 -157t-245.5 -156h-284z" /> +<glyph unicode="&#xb5;" horiz-adv-x="1288" d="M-82 -492l344 1625h387l-129 -617q-18 -78 -18 -141q0 -44 22.5 -65t53.5 -21q52 0 82.5 26t53.5 87t48 180l117 551h387l-240 -1133h-289l6 123h-8q-68 -143 -190 -143q-102 0 -131 77h-8q-10 -134 -48 -303l-53 -246h-387z" /> +<glyph unicode="&#xb6;" horiz-adv-x="1317" d="M102 1042q0 256 107.5 385t343.5 129h633v-1816h-191v1587h-157v-1587h-191v819q-54 -18 -125 -18q-216 0 -318 125t-102 376z" /> +<glyph unicode="&#xb7;" horiz-adv-x="627" d="M115 684q0 106 65 168.5t178 62.5q82 0 131.5 -40.5t49.5 -114.5q0 -117 -65.5 -173.5t-178.5 -56.5q-86 0 -133 40t-47 114z" /> +<glyph unicode="&#xb8;" horiz-adv-x="383" d="M-221 -258q30 -9 78.5 -18t72.5 -9q68 0 68 49q0 73 -145 101l75 135h205l-24 -41q178 -37 178 -195q0 -121 -82.5 -188.5t-233.5 -67.5q-115 0 -192 29v205z" /> +<glyph unicode="&#xb9;" horiz-adv-x="848" d="M115 1202l426 260h252l-187 -878h-317l82 364q21 102 55 207l-74 -59l-119 -78z" /> +<glyph unicode="&#xba;" horiz-adv-x="817" d="M139 1004q0 213 116.5 344t317.5 131q143 0 222 -79t79 -218q0 -134 -51 -237t-149.5 -160.5t-231.5 -57.5q-144 0 -223.5 75.5t-79.5 201.5zM412 1016q0 -84 55 -84q59 0 97 70.5t38 179.5q0 45 -11.5 68.5t-43.5 23.5q-60 0 -97.5 -73t-37.5 -185z" /> +<glyph unicode="&#xbb;" horiz-adv-x="1276" d="M-14 248l276 305l-121 358l332 138l195 -506v-11l-424 -497zM543 248l266 334l-111 329l334 138l182 -478v-10l-407 -518z" /> +<glyph unicode="&#xbc;" horiz-adv-x="1991" d="M921 122l31 178l490 577h325l-119 -557h113l-41 -198h-113l-26 -123h-289l27 123h-398zM1198 320h162q62 239 73 274t15 44q-13 -18 -35 -48.5t-215 -269.5zM195 0l1089 1462h291l-1083 -1462h-297zM79 1202l426 260h252l-187 -878h-317l82 364q21 102 55 207l-74 -59 l-119 -78z" /> +<glyph unicode="&#xbd;" horiz-adv-x="1991" d="M1002 -1l43 204l276 211q108 83 144 124t36 75q0 51 -63 51q-35 0 -85 -18t-104 -62l-118 191q84 65 172.5 94t216.5 29q134 0 218.5 -61t84.5 -156q0 -70 -31.5 -129.5t-102 -121t-251.5 -175.5h319l-51 -256h-704zM104 1202l426 260h252l-187 -878h-317l82 364 q21 102 55 207l-74 -59l-119 -78zM219 0l1089 1462h291l-1083 -1462h-297z" /> +<glyph unicode="&#xbe;" horiz-adv-x="1991" d="M968 122l31 178l490 577h325l-119 -557h113l-41 -198h-113l-26 -123h-289l27 123h-398zM1245 320h162q62 239 73 274t15 44q-13 -18 -35 -48.5t-215 -269.5zM195 639v225q63 -43 131.5 -62.5t124.5 -19.5q151 0 151 80q0 68 -113 68h-120l43 194h96q71 0 114.5 21.5 t43.5 66.5q0 28 -22 43t-54 15q-79 0 -185 -66l-100 182q83 52 161 73.5t181 21.5q137 0 220 -57t83 -152q0 -91 -55.5 -146t-175.5 -84v-8q92 -23 129 -69.5t37 -112.5q0 -127 -104 -205t-275 -78q-106 0 -177.5 16t-133.5 54zM363 0l1089 1462h291l-1083 -1462h-297z" /> +<glyph unicode="&#xbf;" horiz-adv-x="999" d="M-84 -16q0 89 27.5 155.5t77.5 119t172 126.5q100 60 142.5 101t55.5 83l15 43h315l-12 -63q-15 -82 -43 -140t-72.5 -104.5t-138.5 -107.5q-89 -58 -125.5 -95t-36.5 -77q0 -37 22.5 -53.5t67.5 -16.5q124 0 313 108l119 -282q-227 -135 -461 -135q-201 0 -319.5 90 t-118.5 248zM285 -324zM377 924q0 109 64 169t173 60q89 0 138 -39.5t49 -112.5q0 -107 -65 -170t-179 -63q-87 0 -133.5 40.5t-46.5 115.5z" /> +<glyph unicode="&#xc0;" horiz-adv-x="1384" d="M-121 0l744 1462h503l123 -1462h-381l-10 274h-448l-125 -274h-406zM553 586h293l-17 424l-2 86q0 75 4 131q-24 -86 -61 -166zM551 1886v21h396q29 -157 94 -303v-25h-236q-82 75 -152 159t-102 148z" /> +<glyph unicode="&#xc1;" horiz-adv-x="1384" d="M-121 0l744 1462h503l123 -1462h-381l-10 274h-448l-125 -274h-406zM553 586h293l-17 424l-2 86q0 75 4 131q-24 -86 -61 -166zM709 1579v23q123 102 282 305h439v-15q-45 -54 -191.5 -157t-245.5 -156h-284z" /> +<glyph unicode="&#xc2;" horiz-adv-x="1384" d="M-121 0l744 1462h503l123 -1462h-381l-10 274h-448l-125 -274h-406zM553 586h293l-17 424l-2 86q0 75 4 131q-24 -86 -61 -166zM399 1579v23q79 72 170 162.5t139 142.5h447q26 -59 78 -149.5t102 -155.5v-23h-266q-46 41 -156 174q-140 -110 -240 -174h-274z" /> +<glyph unicode="&#xc3;" horiz-adv-x="1384" d="M-121 0l744 1462h503l123 -1462h-381l-10 274h-448l-125 -274h-406zM553 586h293l-17 424l-2 86q0 75 4 131q-24 -86 -61 -166zM459 1575q32 172 108.5 257t204.5 85q34 0 59.5 -6.5t94.5 -42.5q31 -17 66 -33t67 -16q78 0 115 100h190q-34 -172 -112.5 -257t-208.5 -85 q-33 0 -65 8t-61 22t-46 23q-73 45 -127 45q-31 0 -60.5 -27t-36.5 -73h-188z" /> +<glyph unicode="&#xc4;" horiz-adv-x="1384" d="M-121 0l744 1462h503l123 -1462h-381l-10 274h-448l-125 -274h-406zM553 586h293l-17 424l-2 86q0 75 4 131q-24 -86 -61 -166zM502 1722q0 187 201 187q170 0 170 -125q0 -189 -201 -189q-88 0 -129 31t-41 96zM989 1722q0 187 201 187q168 0 168 -125q0 -97 -49.5 -143 t-149.5 -46q-88 0 -129 31t-41 96z" /> +<glyph unicode="&#xc5;" horiz-adv-x="1384" d="M-121 0l744 1462h503l123 -1462h-381l-10 274h-448l-125 -274h-406zM553 586h293l-17 424l-2 86q0 75 4 131q-24 -86 -61 -166zM608 1550q0 114 73.5 184t195.5 70q118 0 193 -70.5t75 -181.5q0 -113 -74.5 -183.5t-193.5 -70.5q-121 0 -195 68.5t-74 183.5zM788 1550 q0 -37 23.5 -60.5t65.5 -23.5q39 0 63.5 25t24.5 59q0 38 -26.5 62t-61.5 24q-36 0 -62.5 -24t-26.5 -62z" /> +<glyph unicode="&#xc6;" horiz-adv-x="1937" d="M-125 0l909 1462h1213l-66 -317h-477l-47 -230h444l-71 -317h-445l-57 -276h477l-67 -322h-869l58 274h-418l-170 -274h-414zM662 602h286l113 543h-68z" /> +<glyph unicode="&#xc7;" horiz-adv-x="1290" d="M104 549q0 266 101.5 488t276 335t399.5 113q265 0 481 -131l-148 -305q-93 55 -171 82.5t-162 27.5q-108 0 -195 -78t-136.5 -215t-49.5 -297q0 -134 56 -200t161 -66q83 0 168 20.5t200 69.5v-323q-203 -90 -440 -90q-260 0 -400.5 148.5t-140.5 420.5zM305 -258 q30 -9 78.5 -18t72.5 -9q68 0 68 49q0 73 -145 101l75 135h205l-24 -41q178 -37 178 -195q0 -121 -82.5 -188.5t-233.5 -67.5q-115 0 -192 29v205z" /> +<glyph unicode="&#xc8;" horiz-adv-x="1151" d="M33 0l309 1462h868l-65 -317h-477l-47 -230h444l-72 -317h-444l-57 -276h477l-68 -322h-868zM443 1886v21h396q29 -157 94 -303v-25h-236q-82 75 -152 159t-102 148z" /> +<glyph unicode="&#xc9;" horiz-adv-x="1151" d="M33 0l309 1462h868l-65 -317h-477l-47 -230h444l-72 -317h-444l-57 -276h477l-68 -322h-868zM578 1579v23q123 102 282 305h439v-15q-45 -54 -191.5 -157t-245.5 -156h-284z" /> +<glyph unicode="&#xca;" horiz-adv-x="1151" d="M33 0l309 1462h868l-65 -317h-477l-47 -230h444l-72 -317h-444l-57 -276h477l-68 -322h-868zM303 1579v23q79 72 170 162.5t139 142.5h447q26 -59 78 -149.5t102 -155.5v-23h-266q-46 41 -156 174q-140 -110 -240 -174h-274z" /> +<glyph unicode="&#xcb;" horiz-adv-x="1151" d="M33 0l309 1462h868l-65 -317h-477l-47 -230h444l-72 -317h-444l-57 -276h477l-68 -322h-868zM383 1722q0 187 201 187q170 0 170 -125q0 -189 -201 -189q-88 0 -129 31t-41 96zM870 1722q0 187 201 187q168 0 168 -125q0 -97 -49.5 -143t-149.5 -46q-88 0 -129 31t-41 96 z" /> +<glyph unicode="&#xcc;" horiz-adv-x="727" d="M31 0l309 1462h397l-309 -1462h-397zM259 1886v21h396q29 -157 94 -303v-25h-236q-82 75 -152 159t-102 148z" /> +<glyph unicode="&#xcd;" horiz-adv-x="727" d="M31 0l309 1462h397l-309 -1462h-397zM345 1579v23q123 102 282 305h439v-15q-45 -54 -191.5 -157t-245.5 -156h-284z" /> +<glyph unicode="&#xce;" horiz-adv-x="727" d="M31 0l309 1462h397l-309 -1462h-397zM79 1579v23q79 72 170 162.5t139 142.5h447q26 -59 78 -149.5t102 -155.5v-23h-266q-46 41 -156 174q-140 -110 -240 -174h-274z" /> +<glyph unicode="&#xcf;" horiz-adv-x="727" d="M31 0l309 1462h397l-309 -1462h-397zM159 1722q0 187 201 187q170 0 170 -125q0 -189 -201 -189q-88 0 -129 31t-41 96zM646 1722q0 187 201 187q168 0 168 -125q0 -97 -49.5 -143t-149.5 -46q-88 0 -129 31t-41 96z" /> +<glyph unicode="&#xd0;" horiz-adv-x="1401" d="M10 563l70 320h139l123 579h430q271 0 418 -143.5t147 -409.5q0 -434 -213 -671.5t-598 -237.5h-493l119 563h-142zM494 324h69q111 0 198 71.5t134 204t47 301.5q0 116 -54 179t-151 63h-71l-56 -260h178l-69 -320h-176z" /> +<glyph unicode="&#xd1;" horiz-adv-x="1618" d="M33 0l309 1462h455l286 -983h9q29 236 57 371l131 612h348l-309 -1462h-455l-289 1028h-8q-29 -291 -57 -418l-129 -610h-348zM553 1575q32 172 108.5 257t204.5 85q34 0 59.5 -6.5t94.5 -42.5q31 -17 66 -33t67 -16q78 0 115 100h190q-34 -172 -112.5 -257t-208.5 -85 q-33 0 -65 8t-61 22t-46 23q-73 45 -127 45q-31 0 -60.5 -27t-36.5 -73h-188z" /> +<glyph unicode="&#xd2;" horiz-adv-x="1509" d="M104 543q0 265 103 487t280.5 338.5t409.5 116.5q260 0 404.5 -148.5t144.5 -414.5t-99.5 -486.5t-274.5 -338t-406 -117.5q-269 0 -415.5 149t-146.5 414zM500 545q0 -242 200 -242q95 0 176.5 83t128 224t46.5 308q0 114 -48 178.5t-139 64.5q-99 0 -182 -84 t-132.5 -231t-49.5 -301zM612 1886v21h396q29 -157 94 -303v-25h-236q-82 75 -152 159t-102 148z" /> +<glyph unicode="&#xd3;" horiz-adv-x="1509" d="M104 543q0 265 103 487t280.5 338.5t409.5 116.5q260 0 404.5 -148.5t144.5 -414.5t-99.5 -486.5t-274.5 -338t-406 -117.5q-269 0 -415.5 149t-146.5 414zM500 545q0 -242 200 -242q95 0 176.5 83t128 224t46.5 308q0 114 -48 178.5t-139 64.5q-99 0 -182 -84 t-132.5 -231t-49.5 -301zM717 1579v23q123 102 282 305h439v-15q-45 -54 -191.5 -157t-245.5 -156h-284z" /> +<glyph unicode="&#xd4;" horiz-adv-x="1509" d="M104 543q0 265 103 487t280.5 338.5t409.5 116.5q260 0 404.5 -148.5t144.5 -414.5t-99.5 -486.5t-274.5 -338t-406 -117.5q-269 0 -415.5 149t-146.5 414zM500 545q0 -242 200 -242q95 0 176.5 83t128 224t46.5 308q0 114 -48 178.5t-139 64.5q-99 0 -182 -84 t-132.5 -231t-49.5 -301zM432 1579v23q79 72 170 162.5t139 142.5h447q26 -59 78 -149.5t102 -155.5v-23h-266q-46 41 -156 174q-140 -110 -240 -174h-274z" /> +<glyph unicode="&#xd5;" horiz-adv-x="1509" d="M104 543q0 265 103 487t280.5 338.5t409.5 116.5q260 0 404.5 -148.5t144.5 -414.5t-99.5 -486.5t-274.5 -338t-406 -117.5q-269 0 -415.5 149t-146.5 414zM500 545q0 -242 200 -242q95 0 176.5 83t128 224t46.5 308q0 114 -48 178.5t-139 64.5q-99 0 -182 -84 t-132.5 -231t-49.5 -301zM489 1575q32 172 108.5 257t204.5 85q34 0 59.5 -6.5t94.5 -42.5q31 -17 66 -33t67 -16q78 0 115 100h190q-34 -172 -112.5 -257t-208.5 -85q-33 0 -65 8t-61 22t-46 23q-73 45 -127 45q-31 0 -60.5 -27t-36.5 -73h-188z" /> +<glyph unicode="&#xd6;" horiz-adv-x="1509" d="M104 543q0 265 103 487t280.5 338.5t409.5 116.5q260 0 404.5 -148.5t144.5 -414.5t-99.5 -486.5t-274.5 -338t-406 -117.5q-269 0 -415.5 149t-146.5 414zM500 545q0 -242 200 -242q95 0 176.5 83t128 224t46.5 308q0 114 -48 178.5t-139 64.5q-99 0 -182 -84 t-132.5 -231t-49.5 -301zM512 1722q0 187 201 187q170 0 170 -125q0 -189 -201 -189q-88 0 -129 31t-41 96zM999 1722q0 187 201 187q168 0 168 -125q0 -97 -49.5 -143t-149.5 -46q-88 0 -129 31t-41 96z" /> +<glyph unicode="&#xd7;" horiz-adv-x="1159" d="M102 1010l187 190l289 -285l292 285l191 -184l-293 -293l287 -291l-185 -188l-292 288l-289 -286l-185 188l283 289z" /> +<glyph unicode="&#xd8;" horiz-adv-x="1509" d="M94 31l117 145q-107 141 -107 367q0 262 101 484.5t275.5 340t398.5 117.5q182 0 315 -72l92 115l156 -119l-99 -125q103 -143 103 -362q0 -258 -98.5 -480.5t-271 -342t-392.5 -119.5q-192 0 -324 69l-106 -135zM500 539l467 589q-45 33 -115 33q-94 0 -175 -82 t-129 -224t-48 -306v-10zM586 332q46 -29 114 -29q95 0 176 81.5t128 222.5t47 308z" /> +<glyph unicode="&#xd9;" horiz-adv-x="1436" d="M125 410q0 64 12 129l199 923h391l-195 -913q-14 -68 -14 -115q0 -127 121 -127q94 0 147.5 64.5t81.5 197.5l191 893h391l-199 -932q-59 -281 -225 -415.5t-451 -134.5q-134 0 -236.5 55t-158 154t-55.5 221zM555 1886v21h396q29 -157 94 -303v-25h-236q-82 75 -152 159 t-102 148z" /> +<glyph unicode="&#xda;" horiz-adv-x="1436" d="M125 410q0 64 12 129l199 923h391l-195 -913q-14 -68 -14 -115q0 -127 121 -127q94 0 147.5 64.5t81.5 197.5l191 893h391l-199 -932q-59 -281 -225 -415.5t-451 -134.5q-134 0 -236.5 55t-158 154t-55.5 221zM725 1579v23q123 102 282 305h439v-15q-45 -54 -191.5 -157 t-245.5 -156h-284z" /> +<glyph unicode="&#xdb;" horiz-adv-x="1436" d="M125 410q0 64 12 129l199 923h391l-195 -913q-14 -68 -14 -115q0 -127 121 -127q94 0 147.5 64.5t81.5 197.5l191 893h391l-199 -932q-59 -281 -225 -415.5t-451 -134.5q-134 0 -236.5 55t-158 154t-55.5 221zM440 1579v23q79 72 170 162.5t139 142.5h447 q26 -59 78 -149.5t102 -155.5v-23h-266q-46 41 -156 174q-140 -110 -240 -174h-274z" /> +<glyph unicode="&#xdc;" horiz-adv-x="1436" d="M125 410q0 64 12 129l199 923h391l-195 -913q-14 -68 -14 -115q0 -127 121 -127q94 0 147.5 64.5t81.5 197.5l191 893h391l-199 -932q-59 -281 -225 -415.5t-451 -134.5q-134 0 -236.5 55t-158 154t-55.5 221zM533 1722q0 187 201 187q170 0 170 -125q0 -189 -201 -189 q-88 0 -129 31t-41 96zM1020 1722q0 187 201 187q168 0 168 -125q0 -97 -49.5 -143t-149.5 -46q-88 0 -129 31t-41 96z" /> +<glyph unicode="&#xdd;" horiz-adv-x="1237" d="M164 1462h403l90 -542l312 542h436l-612 -895l-121 -567h-391l120 567zM615 1579v23q123 102 282 305h439v-15q-45 -54 -191.5 -157t-245.5 -156h-284z" /> +<glyph unicode="&#xde;" horiz-adv-x="1276" d="M33 0l309 1462h391l-45 -211q251 0 385.5 -114t134.5 -326q0 -250 -170.5 -393.5t-470.5 -143.5h-86l-57 -274h-391zM551 594h63q94 0 148.5 49t54.5 156q0 58 -41.5 95.5t-107.5 37.5h-45z" /> +<glyph unicode="&#xdf;" horiz-adv-x="1460" d="M-260 -162q63 -18 117 -18q74 0 111.5 30t51.5 95l244 1151q53 249 201.5 360t417.5 111q243 0 379.5 -99t136.5 -274q0 -118 -51 -198t-162 -132q-117 -56 -117 -102q0 -29 20.5 -50.5t87.5 -56.5q95 -51 140 -118t45 -164q0 -117 -58.5 -205.5t-170 -138t-271.5 -49.5 q-161 0 -274 45v299q59 -29 136.5 -45.5t133.5 -16.5q59 0 87 22t28 50q0 32 -19.5 53.5t-113.5 83.5q-88 56 -127 111.5t-39 130.5q0 92 42 150.5t165 125.5q71 40 100 76t29 80q0 58 -41.5 88.5t-116.5 30.5q-78 0 -132.5 -50t-74.5 -147l-252 -1184 q-43 -192 -153.5 -283.5t-292.5 -91.5q-110 0 -207 27v303z" /> +<glyph unicode="&#xe0;" d="M84 412q0 179 73 365t184.5 281t246.5 95q84 0 148 -37.5t114 -122.5h8l53 140h310l-240 -1133h-309l10 123h-8q-56 -78 -121 -110.5t-147 -32.5q-158 0 -240 111.5t-82 320.5zM479 434q0 -143 86 -143q50 0 95.5 58.5t72.5 156.5t27 192q0 65 -20 104.5t-62 39.5 q-76 0 -137.5 -126.5t-61.5 -281.5zM400 1548v21h396q29 -157 94 -303v-25h-236q-82 75 -152 159t-102 148z" /> +<glyph unicode="&#xe1;" d="M84 412q0 179 73 365t184.5 281t246.5 95q84 0 148 -37.5t114 -122.5h8l53 140h310l-240 -1133h-309l10 123h-8q-56 -78 -121 -110.5t-147 -32.5q-158 0 -240 111.5t-82 320.5zM479 434q0 -143 86 -143q50 0 95.5 58.5t72.5 156.5t27 192q0 65 -20 104.5t-62 39.5 q-76 0 -137.5 -126.5t-61.5 -281.5zM531 1241v23q123 102 282 305h439v-15q-45 -54 -191.5 -157t-245.5 -156h-284z" /> +<glyph unicode="&#xe2;" d="M84 412q0 179 73 365t184.5 281t246.5 95q84 0 148 -37.5t114 -122.5h8l53 140h310l-240 -1133h-309l10 123h-8q-56 -78 -121 -110.5t-147 -32.5q-158 0 -240 111.5t-82 320.5zM479 434q0 -143 86 -143q50 0 95.5 58.5t72.5 156.5t27 192q0 65 -20 104.5t-62 39.5 q-76 0 -137.5 -126.5t-61.5 -281.5zM262 1238v23q79 72 170 162.5t139 142.5h447q26 -59 78 -149.5t102 -155.5v-23h-266q-46 41 -156 174q-140 -110 -240 -174h-274z" /> +<glyph unicode="&#xe3;" d="M84 412q0 179 73 365t184.5 281t246.5 95q84 0 148 -37.5t114 -122.5h8l53 140h310l-240 -1133h-309l10 123h-8q-56 -78 -121 -110.5t-147 -32.5q-158 0 -240 111.5t-82 320.5zM479 434q0 -143 86 -143q50 0 95.5 58.5t72.5 156.5t27 192q0 65 -20 104.5t-62 39.5 q-76 0 -137.5 -126.5t-61.5 -281.5zM301 1237q32 172 108.5 257t204.5 85q34 0 59.5 -6.5t94.5 -42.5q31 -17 66 -33t67 -16q78 0 115 100h190q-34 -172 -112.5 -257t-208.5 -85q-33 0 -65 8t-61 22t-46 23q-73 45 -127 45q-31 0 -60.5 -27t-36.5 -73h-188z" /> +<glyph unicode="&#xe4;" d="M84 412q0 179 73 365t184.5 281t246.5 95q84 0 148 -37.5t114 -122.5h8l53 140h310l-240 -1133h-309l10 123h-8q-56 -78 -121 -110.5t-147 -32.5q-158 0 -240 111.5t-82 320.5zM479 434q0 -143 86 -143q50 0 95.5 58.5t72.5 156.5t27 192q0 65 -20 104.5t-62 39.5 q-76 0 -137.5 -126.5t-61.5 -281.5zM331 1384q0 187 201 187q170 0 170 -125q0 -189 -201 -189q-88 0 -129 31t-41 96zM818 1384q0 187 201 187q168 0 168 -125q0 -97 -49.5 -143t-149.5 -46q-88 0 -129 31t-41 96z" /> +<glyph unicode="&#xe5;" d="M84 412q0 179 73 365t184.5 281t246.5 95q84 0 148 -37.5t114 -122.5h8l53 140h310l-240 -1133h-309l10 123h-8q-56 -78 -121 -110.5t-147 -32.5q-158 0 -240 111.5t-82 320.5zM479 434q0 -143 86 -143q50 0 95.5 58.5t72.5 156.5t27 192q0 65 -20 104.5t-62 39.5 q-76 0 -137.5 -126.5t-61.5 -281.5zM488 1489q0 114 73.5 184t195.5 70q118 0 193 -70.5t75 -181.5q0 -113 -74.5 -183.5t-193.5 -70.5q-121 0 -195 68.5t-74 183.5zM668 1489q0 -37 23.5 -60.5t65.5 -23.5q39 0 63.5 25t24.5 59q0 38 -26.5 62t-61.5 24q-36 0 -62.5 -24 t-26.5 -62z" /> +<glyph unicode="&#xe6;" horiz-adv-x="1788" d="M84 412q0 179 73 365t184.5 281t246.5 95q92 0 152 -38t110 -122h8l53 140h207v-95q58 56 132.5 85.5t146.5 29.5q157 0 251.5 -86.5t94.5 -228.5q0 -201 -157 -308.5t-451 -107.5h-60v-16q0 -148 164 -148q79 0 155 23.5t173 74.5v-274q-99 -58 -182.5 -80t-192.5 -22 q-179 0 -262 112l-31 -92h-227l10 123h-8q-56 -78 -121 -110.5t-147 -32.5q-158 0 -240 111.5t-82 320.5zM479 434q0 -143 86 -143q76 0 134.5 123t58.5 284q0 65 -23 104.5t-65 39.5q-49 0 -93 -57.5t-71 -155t-27 -195.5zM1114 664h29q109 0 171 41.5t62 109.5 q0 32 -20 54t-64 22q-61 0 -114 -69.5t-64 -157.5z" /> +<glyph unicode="&#xe7;" horiz-adv-x="1032" d="M84 442q0 201 76.5 364.5t215 255t314.5 91.5q195 0 367 -80l-123 -287q-133 60 -225 60q-62 0 -115 -48t-87 -143.5t-34 -187.5q0 -91 30 -133.5t95 -42.5q72 0 139.5 23t143.5 63v-307q-80 -44 -168.5 -67t-206.5 -23q-199 0 -310.5 120.5t-111.5 341.5zM176 -258 q30 -9 78.5 -18t72.5 -9q68 0 68 49q0 73 -145 101l75 135h205l-24 -41q178 -37 178 -195q0 -121 -82.5 -188.5t-233.5 -67.5q-115 0 -192 29v205z" /> +<glyph unicode="&#xe8;" horiz-adv-x="1186" d="M84 428q0 211 83.5 380.5t229 257t336.5 87.5q190 0 299 -86t109 -229q0 -201 -156.5 -308.5t-452.5 -107.5h-59v-16q0 -148 164 -148q79 0 155 23.5t173 74.5v-274q-112 -57 -209 -79.5t-224 -22.5q-212 0 -330 118.5t-118 329.5zM512 664h29q109 0 171 41.5t62 109.5 q0 32 -20 54t-64 22q-61 0 -114 -69.5t-64 -157.5zM429 1548v21h396q29 -157 94 -303v-25h-236q-82 75 -152 159t-102 148z" /> +<glyph unicode="&#xe9;" horiz-adv-x="1186" d="M84 428q0 211 83.5 380.5t229 257t336.5 87.5q190 0 299 -86t109 -229q0 -201 -156.5 -308.5t-452.5 -107.5h-59v-16q0 -148 164 -148q79 0 155 23.5t173 74.5v-274q-112 -57 -209 -79.5t-224 -22.5q-212 0 -330 118.5t-118 329.5zM512 664h29q109 0 171 41.5t62 109.5 q0 32 -20 54t-64 22q-61 0 -114 -69.5t-64 -157.5zM523 1241v23q123 102 282 305h439v-15q-45 -54 -191.5 -157t-245.5 -156h-284z" /> +<glyph unicode="&#xea;" horiz-adv-x="1186" d="M84 428q0 211 83.5 380.5t229 257t336.5 87.5q190 0 299 -86t109 -229q0 -201 -156.5 -308.5t-452.5 -107.5h-59v-16q0 -148 164 -148q79 0 155 23.5t173 74.5v-274q-112 -57 -209 -79.5t-224 -22.5q-212 0 -330 118.5t-118 329.5zM512 664h29q109 0 171 41.5t62 109.5 q0 32 -20 54t-64 22q-61 0 -114 -69.5t-64 -157.5zM277 1241v23q79 72 170 162.5t139 142.5h447q26 -59 78 -149.5t102 -155.5v-23h-266q-46 41 -156 174q-140 -110 -240 -174h-274z" /> +<glyph unicode="&#xeb;" horiz-adv-x="1186" d="M84 428q0 211 83.5 380.5t229 257t336.5 87.5q190 0 299 -86t109 -229q0 -201 -156.5 -308.5t-452.5 -107.5h-59v-16q0 -148 164 -148q79 0 155 23.5t173 74.5v-274q-112 -57 -209 -79.5t-224 -22.5q-212 0 -330 118.5t-118 329.5zM512 664h29q109 0 171 41.5t62 109.5 q0 32 -20 54t-64 22q-61 0 -114 -69.5t-64 -157.5zM336 1384q0 187 201 187q170 0 170 -125q0 -189 -201 -189q-88 0 -129 31t-41 96zM823 1384q0 187 201 187q168 0 168 -125q0 -97 -49.5 -143t-149.5 -46q-88 0 -129 31t-41 96z" /> +<glyph unicode="&#xec;" horiz-adv-x="666" d="M23 0l239 1133h389l-241 -1133h-387zM167 1548v21h396q29 -157 94 -303v-25h-236q-82 75 -152 159t-102 148z" /> +<glyph unicode="&#xed;" horiz-adv-x="666" d="M23 0l239 1133h389l-241 -1133h-387zM294 1241v23q123 102 282 305h439v-15q-45 -54 -191.5 -157t-245.5 -156h-284z" /> +<glyph unicode="&#xee;" horiz-adv-x="666" d="M23 0l239 1133h389l-241 -1133h-387zM-7 1241v23q79 72 170 162.5t139 142.5h447q26 -59 78 -149.5t102 -155.5v-23h-266q-46 41 -156 174q-140 -110 -240 -174h-274z" /> +<glyph unicode="&#xef;" horiz-adv-x="666" d="M23 0l239 1133h389l-241 -1133h-387zM91 1384q0 187 201 187q170 0 170 -125q0 -189 -201 -189q-88 0 -129 31t-41 96zM578 1384q0 187 201 187q168 0 168 -125q0 -97 -49.5 -143t-149.5 -46q-88 0 -129 31t-41 96z" /> +<glyph unicode="&#xf0;" horiz-adv-x="1155" d="M84 426q0 170 62.5 305t178.5 209t267 74q130 0 203 -88l10 4q-19 142 -90 246l-273 -127l-82 168l220 102q-29 25 -95 74l115 180q136 -61 231 -137l238 110l82 -166l-184 -90q71 -88 114 -249t43 -324q0 -360 -154.5 -548.5t-449.5 -188.5q-201 0 -318.5 119 t-117.5 327zM471 408q0 -148 84 -148q53 0 93 44.5t63.5 119t23.5 147.5q0 76 -18.5 119t-65.5 43q-81 0 -130.5 -101t-49.5 -224z" /> +<glyph unicode="&#xf1;" horiz-adv-x="1274" d="M23 0l239 1133h309l-12 -158h8q55 95 129.5 136.5t182.5 41.5q141 0 220 -85.5t79 -236.5q0 -106 -25 -229l-127 -602h-387l129 618q18 78 18 142q0 43 -22 64.5t-53 21.5q-57 0 -105.5 -71t-79.5 -222l-116 -553h-387zM319 1237q32 172 108.5 257t204.5 85 q34 0 59.5 -6.5t94.5 -42.5q31 -17 66 -33t67 -16q78 0 115 100h190q-34 -172 -112.5 -257t-208.5 -85q-33 0 -65 8t-61 22t-46 23q-73 45 -127 45q-31 0 -60.5 -27t-36.5 -73h-188z" /> +<glyph unicode="&#xf2;" d="M84 416q0 210 79.5 379.5t223.5 263.5t336 94q209 0 322.5 -113t113.5 -323t-79.5 -379.5t-223.5 -263.5t-336 -94q-209 0 -322.5 113t-113.5 323zM479 403q0 -133 84 -133q81 0 141 139t60 320q0 66 -23 99.5t-63 33.5q-82 0 -140.5 -139.5t-58.5 -319.5zM404 1548v21 h396q29 -157 94 -303v-25h-236q-82 75 -152 159t-102 148z" /> +<glyph unicode="&#xf3;" d="M84 416q0 210 79.5 379.5t223.5 263.5t336 94q209 0 322.5 -113t113.5 -323t-79.5 -379.5t-223.5 -263.5t-336 -94q-209 0 -322.5 113t-113.5 323zM479 403q0 -133 84 -133q81 0 141 139t60 320q0 66 -23 99.5t-63 33.5q-82 0 -140.5 -139.5t-58.5 -319.5zM533 1241v23 q123 102 282 305h439v-15q-45 -54 -191.5 -157t-245.5 -156h-284z" /> +<glyph unicode="&#xf4;" d="M84 416q0 210 79.5 379.5t223.5 263.5t336 94q209 0 322.5 -113t113.5 -323t-79.5 -379.5t-223.5 -263.5t-336 -94q-209 0 -322.5 113t-113.5 323zM479 403q0 -133 84 -133q81 0 141 139t60 320q0 66 -23 99.5t-63 33.5q-82 0 -140.5 -139.5t-58.5 -319.5zM247 1241v23 q79 72 170 162.5t139 142.5h447q26 -59 78 -149.5t102 -155.5v-23h-266q-46 41 -156 174q-140 -110 -240 -174h-274z" /> +<glyph unicode="&#xf5;" d="M84 416q0 210 79.5 379.5t223.5 263.5t336 94q209 0 322.5 -113t113.5 -323t-79.5 -379.5t-223.5 -263.5t-336 -94q-209 0 -322.5 113t-113.5 323zM479 403q0 -133 84 -133q81 0 141 139t60 320q0 66 -23 99.5t-63 33.5q-82 0 -140.5 -139.5t-58.5 -319.5zM277 1237 q32 172 108.5 257t204.5 85q34 0 59.5 -6.5t94.5 -42.5q31 -17 66 -33t67 -16q78 0 115 100h190q-34 -172 -112.5 -257t-208.5 -85q-33 0 -65 8t-61 22t-46 23q-73 45 -127 45q-31 0 -60.5 -27t-36.5 -73h-188z" /> +<glyph unicode="&#xf6;" d="M84 416q0 210 79.5 379.5t223.5 263.5t336 94q209 0 322.5 -113t113.5 -323t-79.5 -379.5t-223.5 -263.5t-336 -94q-209 0 -322.5 113t-113.5 323zM479 403q0 -133 84 -133q81 0 141 139t60 320q0 66 -23 99.5t-63 33.5q-82 0 -140.5 -139.5t-58.5 -319.5zM317 1384 q0 187 201 187q170 0 170 -125q0 -189 -201 -189q-88 0 -129 31t-41 96zM804 1384q0 187 201 187q168 0 168 -125q0 -97 -49.5 -143t-149.5 -46q-88 0 -129 31t-41 96z" /> +<glyph unicode="&#xf7;" horiz-adv-x="1159" d="M102 586v272h975v-272h-975zM432 373q0 83 41 127.5t117 44.5q74 0 114.5 -44.5t40.5 -127.5q0 -81 -41.5 -126.5t-113.5 -45.5q-74 0 -116 46t-42 126zM432 1071q0 83 41 127.5t117 44.5q74 0 114.5 -44.5t40.5 -127.5q0 -81 -41.5 -126.5t-113.5 -45.5q-74 0 -116 46 t-42 126z" /> +<glyph unicode="&#xf8;" horiz-adv-x="1286" d="M66 -2l112 131q-94 117 -94 287q0 207 81.5 377.5t230.5 265t347 94.5q136 0 250 -57l105 121l127 -109l-105 -123q82 -114 82 -268q0 -208 -81 -377.5t-229 -264.5t-343 -95q-127 0 -238 49l-118 -140zM449 451l335 397q-35 29 -82 29q-67 0 -125 -55t-92 -153t-36 -218 zM518 274q29 -14 72 -14q107 0 172 101.5t74 287.5z" /> +<glyph unicode="&#xf9;" horiz-adv-x="1274" d="M96 301q0 106 25 229l127 603h387l-129 -617q-19 -82 -19 -141q0 -44 22.5 -65t53.5 -21q59 0 107.5 78.5t77.5 214.5l116 551h387l-239 -1133h-310l13 158h-8q-54 -93 -128.5 -135.5t-183.5 -42.5q-141 0 -220 85.5t-79 235.5zM412 1548v21h396q29 -157 94 -303v-25 h-236q-82 75 -152 159t-102 148z" /> +<glyph unicode="&#xfa;" horiz-adv-x="1274" d="M96 301q0 106 25 229l127 603h387l-129 -617q-19 -82 -19 -141q0 -44 22.5 -65t53.5 -21q59 0 107.5 78.5t77.5 214.5l116 551h387l-239 -1133h-310l13 158h-8q-54 -93 -128.5 -135.5t-183.5 -42.5q-141 0 -220 85.5t-79 235.5zM584 1241v23q123 102 282 305h439v-15 q-45 -54 -191.5 -157t-245.5 -156h-284z" /> +<glyph unicode="&#xfb;" horiz-adv-x="1274" d="M96 301q0 106 25 229l127 603h387l-129 -617q-19 -82 -19 -141q0 -44 22.5 -65t53.5 -21q59 0 107.5 78.5t77.5 214.5l116 551h387l-239 -1133h-310l13 158h-8q-54 -93 -128.5 -135.5t-183.5 -42.5q-141 0 -220 85.5t-79 235.5zM285 1241v23q79 72 170 162.5t139 142.5 h447q26 -59 78 -149.5t102 -155.5v-23h-266q-46 41 -156 174q-140 -110 -240 -174h-274z" /> +<glyph unicode="&#xfc;" horiz-adv-x="1274" d="M96 301q0 106 25 229l127 603h387l-129 -617q-19 -82 -19 -141q0 -44 22.5 -65t53.5 -21q59 0 107.5 78.5t77.5 214.5l116 551h387l-239 -1133h-310l13 158h-8q-54 -93 -128.5 -135.5t-183.5 -42.5q-141 0 -220 85.5t-79 235.5zM371 1384q0 187 201 187q170 0 170 -125 q0 -189 -201 -189q-88 0 -129 31t-41 96zM858 1384q0 187 201 187q168 0 168 -125q0 -97 -49.5 -143t-149.5 -46q-88 0 -129 31t-41 96z" /> +<glyph unicode="&#xfd;" horiz-adv-x="1114" d="M-129 -168q46 -12 109 -12q87 0 142.5 36.5t98.5 114.5l23 41l-162 1121h389l43 -562l2 -62v-87h8q37 132 50 165.5t239 545.5h416l-670 -1276q-96 -185 -223 -267t-311 -82q-92 0 -154 17v307zM492 1241v23q123 102 282 305h439v-15q-45 -54 -191.5 -157t-245.5 -156 h-284z" /> +<glyph unicode="&#xfe;" d="M-82 -492l434 2048h387l-49 -231q-38 -175 -90 -301h8q44 59 96.5 94t131.5 35q151 0 237 -112t86 -306q0 -203 -70 -382.5t-185.5 -276t-252.5 -96.5q-143 0 -231 145h-8q-12 -166 -56 -371l-51 -246h-387zM485 434q0 -65 23 -104t65 -39q48 0 92 57t71.5 153t27.5 197 q0 144 -86 144q-50 0 -95 -57t-71.5 -154t-26.5 -197z" /> +<glyph unicode="&#xff;" horiz-adv-x="1114" d="M-129 -168q46 -12 109 -12q87 0 142.5 36.5t98.5 114.5l23 41l-162 1121h389l43 -562l2 -62v-87h8q37 132 50 165.5t239 545.5h416l-670 -1276q-96 -185 -223 -267t-311 -82q-92 0 -154 17v307zM259 1384q0 187 201 187q170 0 170 -125q0 -189 -201 -189q-88 0 -129 31 t-41 96zM746 1384q0 187 201 187q168 0 168 -125q0 -97 -49.5 -143t-149.5 -46q-88 0 -129 31t-41 96z" /> +<glyph unicode="&#x131;" horiz-adv-x="666" d="M23 0l239 1133h389l-241 -1133h-387z" /> +<glyph unicode="&#x152;" horiz-adv-x="1909" d="M104 528q0 196 58.5 379t164.5 313t252.5 197.5t323.5 67.5q94 0 191 -23h874l-67 -319h-478l-47 -225h445l-72 -322h-444l-58 -272h477l-65 -324h-815q-104 -20 -197 -20q-256 0 -399.5 146.5t-143.5 401.5zM500 526q0 -217 182 -217q96 0 180 41l162 762 q-53 49 -154 49q-96 0 -182.5 -88t-137 -235t-50.5 -312z" /> +<glyph unicode="&#x153;" horiz-adv-x="1802" d="M84 416q0 209 79 380t217.5 264t319.5 93q187 0 277 -125q144 125 373 125q188 0 297.5 -86t109.5 -229q0 -203 -157 -309.5t-451 -106.5h-59v-16q0 -148 163 -148q79 0 155 23.5t173 74.5v-274q-114 -58 -210.5 -80t-221.5 -22q-203 0 -295 112q-124 -112 -334 -112 q-209 0 -322.5 113t-113.5 323zM479 403q0 -133 84 -133q81 0 141 139t60 320q0 66 -23 99.5t-63 33.5q-82 0 -140.5 -139.5t-58.5 -319.5zM1128 664h29q110 0 172 41t62 110q0 32 -20.5 54t-63.5 22q-60 0 -112.5 -68t-66.5 -159z" /> +<glyph unicode="&#x178;" horiz-adv-x="1237" d="M164 1462h403l90 -542l312 542h436l-612 -895l-121 -567h-391l120 567zM397 1722q0 187 201 187q170 0 170 -125q0 -189 -201 -189q-88 0 -129 31t-41 96zM884 1722q0 187 201 187q168 0 168 -125q0 -97 -49.5 -143t-149.5 -46q-88 0 -129 31t-41 96z" /> +<glyph unicode="&#x2c6;" horiz-adv-x="1135" d="M254 1241v23q79 72 170 162.5t139 142.5h447q26 -59 78 -149.5t102 -155.5v-23h-266q-46 41 -156 174q-140 -110 -240 -174h-274z" /> +<glyph unicode="&#x2da;" horiz-adv-x="1182" d="M522 1489q0 114 73.5 184t195.5 70q118 0 193 -70.5t75 -181.5q0 -113 -74.5 -183.5t-193.5 -70.5q-121 0 -195 68.5t-74 183.5zM702 1489q0 -37 23.5 -60.5t65.5 -23.5q39 0 63.5 25t24.5 59q0 38 -26.5 62t-61.5 24q-36 0 -62.5 -24t-26.5 -62z" /> +<glyph unicode="&#x2dc;" horiz-adv-x="1135" d="M301 1237q32 172 108.5 257t204.5 85q34 0 59.5 -6.5t94.5 -42.5q31 -17 66 -33t67 -16q78 0 115 100h190q-34 -172 -112.5 -257t-208.5 -85q-33 0 -65 8t-61 22t-46 23q-73 45 -127 45q-31 0 -60.5 -27t-36.5 -73h-188z" /> +<glyph unicode="&#x2000;" horiz-adv-x="959" /> +<glyph unicode="&#x2001;" horiz-adv-x="1919" /> +<glyph unicode="&#x2002;" horiz-adv-x="959" /> +<glyph unicode="&#x2003;" horiz-adv-x="1919" /> +<glyph unicode="&#x2004;" horiz-adv-x="639" /> +<glyph unicode="&#x2005;" horiz-adv-x="479" /> +<glyph unicode="&#x2006;" horiz-adv-x="319" /> +<glyph unicode="&#x2007;" horiz-adv-x="319" /> +<glyph unicode="&#x2008;" horiz-adv-x="239" /> +<glyph unicode="&#x2009;" horiz-adv-x="383" /> +<glyph unicode="&#x200a;" horiz-adv-x="106" /> +<glyph unicode="&#x2010;" horiz-adv-x="674" d="M23 393l63 312h553l-64 -312h-552z" /> +<glyph unicode="&#x2011;" horiz-adv-x="674" d="M23 393l63 312h553l-64 -312h-552z" /> +<glyph unicode="&#x2012;" horiz-adv-x="674" d="M23 393l63 312h553l-64 -312h-552z" /> +<glyph unicode="&#x2013;" horiz-adv-x="983" d="M33 416l57 274h871l-60 -274h-868z" /> +<glyph unicode="&#x2014;" horiz-adv-x="1966" d="M33 416l57 274h1854l-60 -274h-1851z" /> +<glyph unicode="&#x2018;" horiz-adv-x="500" d="M109 983q104 235 258 479h288q-26 -62 -53 -131t-135 -370h-348z" /> +<glyph unicode="&#x2019;" horiz-adv-x="500" d="M94 961q34 81 67.5 167.5t121.5 333.5h348l8 -22q-92 -212 -256 -479h-289z" /> +<glyph unicode="&#x201a;" horiz-adv-x="621" d="M-104 -264q25 59 50 123t138 379h348l8 -23q-94 -223 -256 -479h-288z" /> +<glyph unicode="&#x201c;" horiz-adv-x="997" d="M109 983q104 235 258 479h288q-26 -62 -53 -131t-135 -370h-348zM606 983q109 246 256 479h289q-49 -115 -100 -258l-88 -243h-349z" /> +<glyph unicode="&#x201d;" horiz-adv-x="997" d="M94 961q49 117 100 258l89 243h348l8 -22q-92 -212 -256 -479h-289zM592 961q41 98 99 258l89 243h348l7 -22q-39 -91 -110 -226t-144 -253h-289z" /> +<glyph unicode="&#x201e;" horiz-adv-x="1122" d="M-104 -264q25 59 50 123t138 379h348l8 -23q-94 -223 -256 -479h-288zM397 -264q61 148 147 387l42 115h348l8 -23q-51 -116 -124.5 -251t-133.5 -228h-287z" /> +<glyph unicode="&#x2022;" horiz-adv-x="803" d="M86 688q0 118 47 214t133.5 150t200.5 54q148 0 221.5 -77.5t73.5 -223.5q0 -194 -101.5 -305t-281.5 -111q-137 0 -215 80t-78 219zM594 1133z" /> +<glyph unicode="&#x2026;" horiz-adv-x="1800" d="M12 127q0 109 65 171t179 62q84 0 132 -40t48 -115q0 -118 -60 -174t-190 -56q-78 0 -126 37t-48 115zM600 127q0 109 65 171t179 62q84 0 132 -40t48 -115q0 -118 -60 -174t-190 -56q-78 0 -126 37t-48 115zM1186 127q0 109 65 171t179 62q84 0 132 -40t48 -115 q0 -118 -60 -174t-190 -56q-78 0 -126 37t-48 115z" /> +<glyph unicode="&#x202f;" horiz-adv-x="383" /> +<glyph unicode="&#x2039;" horiz-adv-x="719" d="M61 553v10l408 518l264 -204l-266 -334l111 -330l-334 -137z" /> +<glyph unicode="&#x203a;" horiz-adv-x="719" d="M-14 248l266 334l-111 329l332 138l184 -478v-10l-407 -518z" /> +<glyph unicode="&#x2044;" horiz-adv-x="248" d="M-563 0l1089 1462h291l-1083 -1462h-297z" /> +<glyph unicode="&#x205f;" horiz-adv-x="479" /> +<glyph unicode="&#x2074;" horiz-adv-x="848" d="M16 707l31 178l490 577h325l-119 -557h113l-41 -198h-113l-26 -123h-289l27 123h-398zM293 905h162q62 239 73 274t15 44q-13 -18 -35 -48.5t-215 -269.5z" /> +<glyph unicode="&#x20ac;" horiz-adv-x="1188" d="M53 451l43 204h109l22 123h-106l47 205h117q84 243 243 373.5t377 130.5q115 0 202 -25t173 -80l-154 -282q-120 78 -221 78q-142 0 -219 -195h297l-45 -205h-309q-18 -59 -25 -123h246l-43 -204h-227q0 -82 27.5 -113t105.5 -31q75 0 145 18.5t148 49.5v-330 q-126 -65 -355 -65q-231 0 -341.5 114t-116.5 357h-140z" /> +<glyph unicode="&#x2122;" horiz-adv-x="1577" d="M102 1286v176h537v-176h-170v-545h-197v545h-170zM711 741v721h286l138 -479l149 479h277v-721h-195v400q0 74 6 110h-8l-152 -510h-163l-144 510h-8q6 -64 6 -110v-400h-192z" /> +<glyph unicode="&#xe000;" horiz-adv-x="1135" d="M0 1135h1135v-1135h-1135v1135z" /> +<glyph unicode="&#xfb01;" horiz-adv-x="1505" d="M-209 -162q63 -18 117 -18q74 0 112 30t52 95l190 897h-166l43 190l189 96l16 74q43 192 146.5 278.5t275.5 86.5q80 0 155 -16t128 -42l-99 -264q-64 31 -129 31q-35 0 -59.5 -18.5t-32.5 -53.5l-16 -71h211l-66 -291h-209l-205 -959q-43 -192 -153.5 -283.5 t-292.5 -91.5q-110 0 -207 27v303zM863 0l239 1133h389l-241 -1133h-387zM1149 1382q0 103 59.5 156t166.5 53q91 0 140.5 -36.5t49.5 -104.5q0 -100 -58 -154.5t-167 -54.5q-191 0 -191 141z" /> +<glyph unicode="&#xfb02;" horiz-adv-x="1505" d="M-209 -162q63 -18 117 -18q74 0 112 30t52 95l190 897h-166l43 190l189 96l16 74q43 192 146.5 278.5t275.5 86.5q80 0 155 -16t128 -42l-99 -264q-64 31 -129 31q-35 0 -59.5 -18.5t-32.5 -53.5l-16 -71h211l-66 -291h-209l-205 -959q-43 -192 -153.5 -283.5 t-292.5 -91.5q-110 0 -207 27v303zM863 0l329 1556h387l-329 -1556h-387z" /> +<glyph unicode="&#xfb03;" horiz-adv-x="2163" d="M-209 -162q63 -18 117 -18q74 0 112 30t52 95l190 897h-166l43 190l189 96l16 74q43 192 146.5 278.5t275.5 86.5q80 0 155 -16t128 -42l-99 -264q-64 31 -129 31q-35 0 -59.5 -18.5t-32.5 -53.5l-16 -71h331l17 69q41 185 142.5 275t279.5 90q80 0 155 -16t127 -42 l-98 -264q-64 31 -129 31q-35 0 -59.5 -18.5t-32.5 -53.5l-16 -71h210l-65 -291h-209l-205 -959q-43 -192 -153.5 -283.5t-292.5 -91.5q-110 0 -207 27v303q63 -18 117 -18q74 0 111.5 30t51.5 95l191 897h-330l-205 -959q-43 -192 -153.5 -283.5t-292.5 -91.5 q-110 0 -207 27v303zM1520 0l239 1133h389l-241 -1133h-387zM1806 1382q0 103 59.5 156t166.5 53q91 0 140.5 -36.5t49.5 -104.5q0 -100 -58 -154.5t-167 -54.5q-191 0 -191 141z" /> +<glyph unicode="&#xfb04;" horiz-adv-x="2159" d="M-209 -162q63 -18 117 -18q74 0 112 30t52 95l190 897h-166l43 190l189 96l16 74q43 192 146.5 278.5t275.5 86.5q80 0 155 -16t128 -42l-99 -264q-64 31 -129 31q-35 0 -59.5 -18.5t-32.5 -53.5l-16 -71h331l17 69q41 185 142.5 275t279.5 90q80 0 155 -16t127 -42 l-98 -264q-64 31 -129 31q-35 0 -59.5 -18.5t-32.5 -53.5l-16 -71h210l-65 -291h-209l-205 -959q-43 -192 -153.5 -283.5t-292.5 -91.5q-110 0 -207 27v303q63 -18 117 -18q74 0 111.5 30t51.5 95l191 897h-330l-205 -959q-43 -192 -153.5 -283.5t-292.5 -91.5 q-110 0 -207 27v303zM1516 0l329 1556h387l-329 -1556h-387z" /> +</font> +</defs></svg> +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-ExtraBoldItalic-webfont.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.svg b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.svg @@ -0,0 +1,251 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata> +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom +</metadata> +<defs> +<font id="OpenSansItalic" horiz-adv-x="1128" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="&#x09;" horiz-adv-x="532" /> +<glyph unicode="&#xa0;" horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="530" d="M43 78q0 76 39.5 120t107.5 44q45 0 73 -27.5t28 -81.5q0 -68 -39 -115t-105 -47q-49 0 -76.5 28t-27.5 79zM172 403q49 307 176 1059h207l-274 -1059h-109z" /> +<glyph unicode="&#x22;" horiz-adv-x="791" d="M225 934l72 528h188l-153 -528h-107zM573 934l72 528h189l-154 -528h-107z" /> +<glyph unicode="#" horiz-adv-x="1323" d="M63 430l13 129h284l101 340h-277l13 127h301l123 436h139l-125 -436h305l127 436h133l-125 -436h264l-12 -127h-291l-98 -340h285l-13 -129h-309l-125 -430h-139l129 430h-303l-127 -430h-133l121 430h-261zM500 559h303l96 340h-303z" /> +<glyph unicode="$" d="M72 176v154q82 -41 175.5 -63.5t166.5 -22.5l98 452q-139 49 -201.5 123.5t-62.5 188.5q0 159 108 255t299 113l39 176h133l-39 -178q159 -12 283 -76l-63 -135q-121 63 -248 72l-94 -440q149 -55 212.5 -125t63.5 -178q0 -162 -112.5 -263t-309.5 -123l-49 -225h-133 l49 223q-195 14 -315 72zM401 1010q0 -53 34.5 -97.5t107.5 -70.5l84 393q-108 -11 -167 -69t-59 -156zM549 250q107 13 170 75t63 154q0 54 -33 96t-114 74z" /> +<glyph unicode="%" horiz-adv-x="1624" d="M168 860q0 166 50.5 318.5t136.5 228.5t200 76q116 0 176 -72t60 -205q0 -108 -32 -237.5t-82.5 -217.5t-120.5 -137t-157 -49q-109 0 -170 75t-61 220zM231 0l1086 1462h151l-1085 -1462h-152zM307 864q0 -172 107 -172q52 0 94 39.5t73.5 114t50.5 175t19 171.5 q0 166 -108 166q-66 0 -119 -63t-85 -187.5t-32 -243.5zM909 274q0 166 50.5 318.5t136.5 228.5t200 76q116 0 176 -71.5t60 -204.5q0 -107 -31.5 -236t-82 -217.5t-121 -138t-156.5 -49.5q-110 0 -171 74.5t-61 219.5zM1049 279q0 -173 106 -173q65 0 117 65t86.5 198.5 t34.5 236.5q0 166 -109 166q-67 0 -119.5 -64.5t-84 -188.5t-31.5 -240z" /> +<glyph unicode="&#x26;" horiz-adv-x="1372" d="M66 342q0 148 90 257.5t303 211.5q-103 165 -103 309q0 164 106 264.5t281 100.5q149 0 236.5 -79t87.5 -212q0 -78 -32.5 -137t-87.5 -108t-127.5 -90t-153.5 -83l278 -389q127 110 199 295h168q-101 -236 -283 -412l203 -270h-201l-117 166q-120 -100 -230 -143 t-247 -43q-168 0 -269 96t-101 266zM229 354q0 -106 66.5 -170.5t175.5 -64.5q87 0 168 33t195 124l-306 433q-128 -67 -184 -116t-85.5 -107.5t-29.5 -131.5zM516 1118q0 -120 82 -235q139 71 191 110t83 85t31 104q0 77 -42.5 121.5t-123.5 44.5q-105 0 -163 -60t-58 -170 z" /> +<glyph unicode="'" horiz-adv-x="444" d="M225 934l72 528h188l-153 -528h-107z" /> +<glyph unicode="(" horiz-adv-x="584" d="M82 272q0 339 120 627t384 563h157q-246 -270 -371.5 -570t-125.5 -618q0 -339 114 -598h-131q-147 266 -147 596z" /> +<glyph unicode=")" horiz-adv-x="584" d="M-160 -324q496 551 496 1188q0 341 -113 598h131q146 -269 146 -598q0 -341 -121.5 -629.5t-382.5 -558.5h-156z" /> +<glyph unicode="*" horiz-adv-x="1130" d="M215 1194l55 154l371 -185l41 400l172 -35l-123 -383l422 18l-8 -157l-393 47l180 -383l-166 -52l-113 406l-258 -344l-116 121l309 284z" /> +<glyph unicode="+" d="M127 651v142h389v391h141v-391h390v-142h-390v-387h-141v387h-389z" /> +<glyph unicode="," horiz-adv-x="492" d="M-100 -264q126 286 204 502h187l8 -23q-113 -235 -270 -479h-129z" /> +<glyph unicode="-" horiz-adv-x="639" d="M55 469l35 158h479l-34 -158h-480z" /> +<glyph unicode="." horiz-adv-x="518" d="M43 74q0 77 40.5 122.5t111.5 45.5q43 0 69.5 -26t26.5 -79q0 -71 -40 -118.5t-108 -47.5q-46 0 -73 26t-27 77z" /> +<glyph unicode="/" horiz-adv-x="717" d="M-94 0l813 1462h174l-813 -1462h-174z" /> +<glyph unicode="0" d="M121 477q0 270 82 514.5t216.5 369t307.5 124.5q365 0 365 -471q0 -295 -78.5 -539t-214 -369.5t-314.5 -125.5q-176 0 -270 127.5t-94 369.5zM293 479q0 -172 50 -264t161 -92q115 0 209 114t150.5 328t56.5 453q0 323 -203 323q-113 0 -209 -115.5t-155.5 -323 t-59.5 -423.5z" /> +<glyph unicode="1" d="M303 1178l449 284h149l-313 -1462h-172l196 913q59 261 88 359q-50 -53 -139 -111l-178 -110z" /> +<glyph unicode="2" d="M12 0l31 147l465 420q102 93 176.5 163.5t123 133t72 124t23.5 136.5q0 99 -60 157t-163 58q-77 0 -150.5 -28.5t-162.5 -96.5l-82 115q191 154 413 154q176 0 278.5 -88.5t102.5 -243.5q0 -111 -39.5 -204t-131 -197t-294.5 -281l-352 -307v-8h678l-29 -154h-899z" /> +<glyph unicode="3" d="M47 59v164q94 -49 199 -75.5t190 -26.5q162 0 252 79.5t90 217.5q0 131 -79 198.5t-220 67.5h-131l31 143h139q165 0 274 87t109 227q0 92 -58 146t-157 54q-80 0 -157 -27t-175 -93l-80 118q195 144 424 144q179 0 277 -87t98 -237q0 -156 -101 -264.5t-280 -140.5v-9 q124 -23 195 -106.5t71 -208.5q0 -133 -62 -234.5t-181 -158.5t-283 -57q-210 0 -385 79z" /> +<glyph unicode="4" d="M16 334l29 158l834 978h196l-207 -983h232l-33 -153h-233l-72 -334h-164l74 334h-656zM219 487h486q46 220 78 373t116 445h-8q-17 -29 -66.5 -96.5t-72.5 -96.5z" /> +<glyph unicode="5" d="M80 59v164q164 -102 334 -102q191 0 298 96t107 268q0 126 -73.5 199.5t-204.5 73.5q-48 0 -97 -6.5t-139 -30.5l-74 57l197 684h668l-33 -153h-522l-127 -439q87 23 184 23q182 0 289.5 -104.5t107.5 -282.5q0 -161 -73 -283t-204 -182.5t-308 -60.5q-193 0 -330 79z " /> +<glyph unicode="6" d="M133 424q0 209 60.5 415t163.5 351.5t246 219t327 73.5q111 0 184 -23l-35 -145q-68 22 -170 22q-212 0 -356.5 -149t-212.5 -443h8q59 79 146.5 126t193.5 47q154 0 244 -98.5t90 -270.5q0 -161 -66.5 -294.5t-180.5 -204t-261 -70.5q-182 0 -281.5 115t-99.5 329z M299 416q0 -137 60.5 -216t172.5 -79q94 0 167.5 54t114 149t40.5 208q0 248 -221 248q-66 0 -128 -28.5t-110 -76t-72 -104.5t-24 -155z" /> +<glyph unicode="7" d="M174 0l768 1313h-719l31 149h891l-27 -139l-764 -1323h-180z" /> +<glyph unicode="8" d="M96 346q0 148 95 256t296 184q-95 69 -135.5 144.5t-40.5 171.5q0 111 54.5 198.5t153.5 136t222 48.5q174 0 271.5 -86.5t97.5 -235.5q0 -129 -78 -225t-266 -176q127 -78 180 -165t53 -202q0 -122 -60 -217.5t-172.5 -146.5t-264.5 -51q-190 0 -298 98.5t-108 267.5z M270 354q0 -107 69 -170t181 -63q139 0 222 74t83 196q0 99 -52 174t-165 135q-185 -60 -261.5 -143.5t-76.5 -202.5zM479 1100q0 -82 39 -144t127 -116q161 60 228 131.5t67 173.5q0 90 -57.5 143t-153.5 53q-114 0 -182 -65.5t-68 -175.5z" /> +<glyph unicode="9" d="M98 14v158q134 -47 246 -47q202 0 327 141t189 441h-10q-51 -75 -132.5 -118.5t-180.5 -43.5q-169 0 -261 98.5t-92 288.5q0 153 64.5 280.5t180 199t259.5 71.5q180 0 279.5 -114.5t99.5 -334.5q0 -194 -56 -406.5t-147.5 -360t-221.5 -217.5t-302 -70q-136 0 -242 34z M350 938q0 -124 54.5 -190t162.5 -66q76 0 140 28.5t108.5 81.5t65 114t20.5 151q0 131 -59 207.5t-160 76.5q-150 0 -241 -113t-91 -290z" /> +<glyph unicode=":" horiz-adv-x="518" d="M43 74q0 77 40.5 122.5t111.5 45.5q43 0 69.5 -26t26.5 -79q0 -71 -40 -118.5t-108 -47.5q-46 0 -73 26t-27 77zM203 956q0 77 40 122.5t111 45.5q97 0 97 -104q0 -73 -41.5 -119.5t-106.5 -46.5q-46 0 -73 26.5t-27 75.5z" /> +<glyph unicode=";" horiz-adv-x="518" d="M-100 -264q126 286 204 502h187l8 -23q-113 -235 -270 -479h-129zM203 956q0 77 40 122.5t111 45.5q97 0 97 -104q0 -73 -41.5 -119.5t-106.5 -46.5q-46 0 -73 26.5t-27 75.5z" /> +<glyph unicode="&#x3c;" d="M121 664v98l919 479v-149l-747 -371l747 -328v-151z" /> +<glyph unicode="=" d="M127 444v142h920v-142h-920zM127 858v139h920v-139h-920z" /> +<glyph unicode="&#x3e;" d="M121 242v151l745 328l-745 371v149l919 -479v-98z" /> +<glyph unicode="?" horiz-adv-x="874" d="M158 74q0 77 40 122.5t111 45.5q44 0 70.5 -26t26.5 -79q0 -73 -41.5 -119.5t-106.5 -46.5q-46 0 -73 26t-27 77zM197 1382q92 51 192 76t182 25q167 0 259 -84t92 -238q0 -123 -65.5 -226.5t-225.5 -223.5q-125 -91 -169 -147.5t-67 -160.5h-135q22 130 72.5 213.5 t165.5 174.5q128 100 168 144t63 94t23 112q0 93 -51.5 143.5t-147.5 50.5q-81 0 -155 -25.5t-140 -56.5z" /> +<glyph unicode="@" horiz-adv-x="1735" d="M111 504q0 261 126.5 485.5t343.5 347.5t486 123q191 0 329 -75.5t210.5 -213.5t72.5 -319q0 -179 -55 -324t-155 -227t-222 -82q-197 0 -213 184h-8q-111 -184 -291 -184q-115 0 -180.5 75.5t-65.5 209.5q0 157 68 284t188.5 199t260.5 72q65 0 127.5 -12t150.5 -48 q-64 -242 -98 -368t-31 -172q0 -117 102 -117q78 0 141.5 67t100.5 183.5t37 243.5q0 239 -128 367t-370 128q-228 0 -406.5 -107t-277 -295.5t-98.5 -416.5q0 -270 143.5 -418.5t409.5 -148.5q197 0 420 86v-127q-219 -90 -443 -90q-314 0 -494.5 184.5t-180.5 505.5z M639 518q0 -93 33 -134.5t98 -41.5q187 0 272 315l70 258q-63 23 -127 23q-94 0 -174 -55t-126 -153t-46 -212z" /> +<glyph unicode="A" horiz-adv-x="1137" d="M-117 0l799 1462h174l184 -1462h-170l-57 465h-496l-245 -465h-189zM401 621h394l-35 299q-24 179 -29 350q-37 -88 -80.5 -175t-249.5 -474z" /> +<glyph unicode="B" horiz-adv-x="1225" d="M86 0l309 1462h375q432 0 432 -336q0 -141 -87 -238t-245 -126v-10q115 -32 176.5 -110.5t61.5 -188.5q0 -212 -152 -332.5t-407 -120.5h-463zM287 145h266q181 0 278 80.5t97 227.5q0 116 -74.5 177.5t-214.5 61.5h-236zM434 836h248q156 0 249 73t93 199 q0 104 -66.5 155.5t-209.5 51.5h-211z" /> +<glyph unicode="C" horiz-adv-x="1198" d="M150 537q0 261 105.5 485.5t283.5 342.5t403 118q197 0 348 -80l-69 -141q-138 69 -279 69q-174 0 -311.5 -97t-218 -284.5t-80.5 -408.5q0 -187 97.5 -298.5t268.5 -111.5q139 0 322 57v-149q-86 -31 -164 -45t-188 -14q-242 0 -380 149.5t-138 407.5z" /> +<glyph unicode="D" horiz-adv-x="1364" d="M86 0l309 1462h342q276 0 419.5 -149.5t143.5 -435.5q0 -261 -105 -461t-300 -308t-457 -108h-352zM287 147h162q202 0 355 91.5t234.5 258.5t81.5 382t-103 325.5t-302 110.5h-178z" /> +<glyph unicode="E" horiz-adv-x="1047" d="M86 0l309 1462h735l-32 -153h-566l-98 -469h527l-29 -152h-529l-114 -536h565l-33 -152h-735z" /> +<glyph unicode="F" horiz-adv-x="967" d="M86 0l309 1462h735l-30 -153h-568l-110 -533h528l-32 -153h-529l-131 -623h-172z" /> +<glyph unicode="G" horiz-adv-x="1386" d="M150 528q0 269 101.5 489.5t281.5 343t399 122.5q117 0 219.5 -20t206.5 -64l-66 -152q-77 34 -165.5 59t-194.5 25q-169 0 -307.5 -101.5t-215.5 -283.5t-77 -407q0 -190 102.5 -299t286.5 -109q154 0 260 39l96 444h-289l33 152h459l-154 -711q-216 -75 -419 -75 q-264 0 -410.5 144.5t-146.5 403.5z" /> +<glyph unicode="H" horiz-adv-x="1389" d="M86 0l309 1462h170l-131 -622h660l133 622h168l-310 -1462h-167l143 688h-660l-145 -688h-170z" /> +<glyph unicode="I" horiz-adv-x="559" d="M86 0l311 1462h168l-311 -1462h-168z" /> +<glyph unicode="J" horiz-adv-x="547" d="M-319 -360l6 147q69 -20 145 -20q100 0 165.5 62.5t90.5 182.5l307 1450h170l-309 -1468q-79 -379 -422 -379q-105 0 -153 25z" /> +<glyph unicode="K" horiz-adv-x="1141" d="M86 0l309 1462h170l-151 -710l700 710h209l-639 -637l350 -825h-186q-72 181 -146.5 359.5t-146.5 361.5l-174 -131l-125 -590h-170z" /> +<glyph unicode="L" horiz-adv-x="971" d="M86 0l309 1462h170l-276 -1308h565l-33 -154h-735z" /> +<glyph unicode="M" horiz-adv-x="1714" d="M84 0l309 1462h244l149 -1204h9l659 1204h266l-303 -1462h-174q126 590 193 905.5t94 392.5h-6l-717 -1298h-131l-166 1296h-8q-7 -72 -28.5 -197.5t-37.5 -199.5l-190 -899h-162z" /> +<glyph unicode="N" horiz-adv-x="1438" d="M84 0l309 1462h180l459 -1220h6q30 224 72 405l174 815h164l-309 -1462h-181l-460 1223h-6q-32 -221 -74 -418l-172 -805h-162z" /> +<glyph unicode="O" horiz-adv-x="1475" d="M150 549q0 264 96 482t263.5 336t377.5 118q244 0 384 -154t140 -424q0 -269 -88 -481.5t-252 -329t-379 -116.5q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q152 0 272.5 97.5t190.5 279.5t70 403q0 199 -94 310.5t-261 111.5q-157 0 -281 -101 t-192.5 -281t-68.5 -398z" /> +<glyph unicode="P" horiz-adv-x="1159" d="M86 0l309 1462h330q214 0 324 -94.5t110 -282.5q0 -248 -164 -379t-481 -131h-135l-123 -575h-170zM410 721h133q216 0 328 91t112 267q0 125 -69.5 180.5t-213.5 55.5h-163z" /> +<glyph unicode="Q" horiz-adv-x="1475" d="M150 549q0 264 96 482t263.5 336t377.5 118q244 0 384 -154t140 -424q0 -333 -139 -576t-375 -321l274 -358h-219l-227 330l-17 -2h-16q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q158 0 279 100t187.5 280.5t66.5 399.5q0 199 -94 310.5 t-261 111.5q-157 0 -281 -101t-192.5 -281t-68.5 -398z" /> +<glyph unicode="R" horiz-adv-x="1165" d="M86 0l309 1462h320q446 0 446 -366q0 -348 -368 -449l239 -647h-186l-209 608h-252l-129 -608h-170zM416 754h168q193 0 297 85t104 244q0 121 -67.5 175.5t-219.5 54.5h-166q-102 -494 -116 -559z" /> +<glyph unicode="S" horiz-adv-x="1028" d="M39 43v170q162 -84 340 -84q162 0 257 75.5t95 207.5q0 78 -52.5 137.5t-195.5 140.5q-151 85 -209.5 170t-58.5 201q0 187 132 304.5t347 117.5q99 0 184.5 -19t180.5 -65l-66 -150q-66 38 -148 60t-151 22q-134 0 -215.5 -69.5t-81.5 -188.5q0 -54 17 -92.5t54 -72.5 t142 -95q147 -88 198.5 -138t78 -110.5t26.5 -140.5q0 -211 -140.5 -327.5t-395.5 -116.5q-106 0 -186.5 14.5t-151.5 48.5z" /> +<glyph unicode="T" horiz-adv-x="1020" d="M186 1311l33 151h985l-30 -151h-408l-279 -1311h-172l277 1311h-406z" /> +<glyph unicode="U" horiz-adv-x="1384" d="M164 383q0 81 24 201l189 878h170l-191 -891q-22 -106 -22 -188q0 -117 73 -184.5t218 -67.5q172 0 267.5 87.5t139.5 289.5l205 954h170l-205 -966q-55 -263 -197.5 -389.5t-388.5 -126.5q-230 0 -341 104t-111 299z" /> +<glyph unicode="V" horiz-adv-x="1122" d="M188 1462h170l97 -930q20 -196 20 -335h4q61 144 162 338l479 927h191l-781 -1462h-180z" /> +<glyph unicode="W" horiz-adv-x="1745" d="M223 1462h170l31 -901l2 -88q0 -98 -10 -258h6q89 243 156 383l405 864h178l43 -860q9 -153 9 -304l-1 -83h9q75 224 131 354l387 893h182l-664 -1462h-170l-49 965q-8 136 -8 282h-6q-25 -72 -61 -154.5t-504 -1092.5h-174z" /> +<glyph unicode="X" horiz-adv-x="1063" d="M-104 0l596 776l-263 686h172l203 -563l443 563h186l-555 -694l278 -768h-180l-213 641l-481 -641h-186z" /> +<glyph unicode="Y" horiz-adv-x="1030" d="M188 1462h170l179 -747l489 747h193l-627 -921l-113 -541h-172l119 549z" /> +<glyph unicode="Z" horiz-adv-x="1087" d="M-16 0l28 137l924 1170h-655l32 155h858l-26 -139l-924 -1169h697l-33 -154h-901z" /> +<glyph unicode="[" horiz-adv-x="586" d="M-16 -324l381 1786h387l-31 -141h-227l-318 -1503h227l-32 -142h-387z" /> +<glyph unicode="\" horiz-adv-x="717" d="M221 1462h154l217 -1462h-154z" /> +<glyph unicode="]" horiz-adv-x="586" d="M-150 -324l31 142h225l320 1503h-227l30 141h389l-380 -1786h-388z" /> +<glyph unicode="^" horiz-adv-x="1059" d="M53 553l598 920h109l266 -920h-145l-201 747l-467 -747h-160z" /> +<glyph unicode="_" horiz-adv-x="807" d="M-188 -324l30 140h811l-30 -140h-811z" /> +<glyph unicode="`" horiz-adv-x="1135" d="M575 1548v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="a" horiz-adv-x="1157" d="M98 350q0 208 71 386t196 279t274 101q92 0 164 -49.5t112 -142.5h11l67 172h127l-233 -1096h-133l26 209h-8q-179 -229 -377 -229q-139 0 -218 99t-79 271zM270 346q0 -114 47 -170.5t132 -56.5q97 0 193 92.5t156 241t60 297.5q0 103 -56 164t-147 61 q-104 0 -193.5 -86t-140.5 -233t-51 -310z" /> +<glyph unicode="b" horiz-adv-x="1182" d="M59 0l330 1556h168q-51 -242 -78.5 -370.5t-75.5 -300.5h9q93 118 183.5 173.5t186.5 55.5q141 0 220 -99t79 -272q0 -209 -68.5 -386.5t-191 -277t-276.5 -99.5q-97 0 -170.5 51t-110.5 139h-10l-70 -170h-125zM319 346q0 -110 55.5 -168.5t160.5 -58.5q99 0 184.5 81 t137.5 230.5t52 317.5q0 227 -178 227q-96 0 -195.5 -95t-158 -239t-58.5 -295z" /> +<glyph unicode="c" horiz-adv-x="922" d="M98 389q0 200 74 369t204.5 263.5t293.5 94.5q137 0 268 -51l-47 -141q-120 51 -219 51q-112 0 -204.5 -76.5t-145 -213t-52.5 -296.5q0 -128 66.5 -199t183.5 -71q72 0 136 20t126 47v-143q-124 -63 -276 -63q-194 0 -301 107t-107 302z" /> +<glyph unicode="d" horiz-adv-x="1182" d="M98 350q0 214 72 392t194.5 275t274.5 97q194 0 281 -190h10q17 155 45 274l78 358h166l-330 -1556h-139l22 209h-8q-101 -125 -189 -177t-182 -52q-139 0 -217 98t-78 272zM270 346q0 -227 179 -227q94 0 194 93.5t158.5 239t58.5 296.5q0 111 -54 169t-157 58 q-101 0 -187.5 -82.5t-139 -232t-52.5 -314.5z" /> +<glyph unicode="e" horiz-adv-x="1010" d="M98 391q0 188 74.5 360.5t197.5 268.5t271 96q153 0 230 -66.5t77 -185.5q0 -180 -166 -282.5t-475 -102.5h-33l-4 -80q0 -131 61.5 -204.5t190.5 -73.5q63 0 129.5 18t165.5 66v-146q-94 -44 -166 -61.5t-159 -17.5q-184 0 -289 109t-105 302zM299 618h12 q228 0 349.5 59.5t121.5 172.5q0 53 -36.5 88t-114.5 35q-103 0 -193.5 -94t-138.5 -261z" /> +<glyph unicode="f" horiz-adv-x="641" d="M-229 -330q64 -22 112 -22q76 0 117 62t66 177l227 1082h-193l13 67l206 66l23 100q46 200 127.5 282.5t241.5 82.5q40 0 98 -11.5t90 -25.5l-43 -129q-76 29 -137 29q-87 0 -133.5 -48.5t-75.5 -177.5l-25 -108h238l-25 -127h-237l-232 -1098q-39 -189 -120 -276 t-213 -87q-69 0 -125 21v141z" /> +<glyph unicode="g" horiz-adv-x="1026" d="M-127 -211q0 105 72 182t233 131q-78 41 -78 121q0 69 51 118.5t142 92.5q-63 32 -103 94.5t-40 145.5q0 194 119.5 318t305.5 124q78 0 154 -20h371l-25 -107l-211 -24q41 -62 41 -158q0 -191 -116.5 -304.5t-311.5 -113.5q-55 0 -84 8q-139 -53 -139 -131 q0 -41 33 -54.5t96 -21.5l117 -14q181 -22 262.5 -88t81.5 -194q0 -184 -146 -285t-411 -101q-194 0 -304 73.5t-110 207.5zM35 -195q0 -77 65 -122t193 -45q182 0 284.5 63.5t102.5 179.5q0 62 -54 98t-184 50l-159 16q-120 -25 -184 -88t-64 -152zM313 680 q0 -85 45 -129.5t125 -44.5q79 0 138 42t90.5 115.5t31.5 159.5q0 82 -44 125t-126 43q-78 0 -136.5 -40.5t-91 -113t-32.5 -157.5z" /> +<glyph unicode="h" horiz-adv-x="1182" d="M59 0l330 1556h168q-18 -82 -34.5 -159t-34 -156.5t-38 -166.5t-47.5 -189h11q94 123 185.5 176t191.5 53q131 0 202.5 -72t71.5 -204q0 -62 -23 -166q-39 -193 -145 -672h-168l148 692q18 94 18 135q0 148 -147 148q-89 0 -173.5 -59t-149 -171.5t-97.5 -271.5 l-101 -473h-168z" /> +<glyph unicode="i" horiz-adv-x="520" d="M59 0l234 1096h168l-234 -1096h-168zM340 1376q0 56 32 91.5t83 35.5q88 0 88 -90q0 -55 -33.5 -93t-77.5 -38q-40 0 -66 24.5t-26 69.5z" /> +<glyph unicode="j" horiz-adv-x="520" d="M-258 -330q61 -22 119 -22q125 0 168 205l264 1243h166l-266 -1258q-36 -171 -114.5 -250.5t-213.5 -79.5q-69 0 -123 21v141zM340 1376q0 56 32 91.5t83 35.5q86 0 86 -90q0 -55 -33.5 -93t-77.5 -38q-38 0 -64 24.5t-26 69.5z" /> +<glyph unicode="k" horiz-adv-x="999" d="M57 0l330 1556h170l-129 -602q-57 -266 -102 -395h4l526 537h201l-469 -467l295 -629h-187l-235 524l-152 -123l-82 -401h-170z" /> +<glyph unicode="l" horiz-adv-x="520" d="M57 0l332 1556h168l-332 -1556h-168z" /> +<glyph unicode="m" horiz-adv-x="1786" d="M59 0l234 1096h139l-22 -203h10q87 119 173.5 171t178.5 52q113 0 174 -65t72 -181h8q86 125 183 185.5t196 60.5q127 0 196.5 -68t69.5 -198q0 -68 -22 -178l-144 -672h-170l148 692q20 104 20 146q0 62 -34.5 99.5t-108.5 37.5q-81 0 -160 -58t-138.5 -164.5 t-90.5 -252.5l-107 -500h-168l148 692q18 94 18 135q0 70 -31 109t-106 39q-84 0 -163.5 -60t-140 -171.5t-93.5 -268.5l-101 -475h-168z" /> +<glyph unicode="n" horiz-adv-x="1182" d="M59 0l234 1096h139l-22 -203h10q96 122 185.5 172.5t185.5 50.5q127 0 200.5 -69.5t73.5 -194.5q0 -79 -23 -180l-143 -672h-170l148 692q20 104 20 144q0 63 -35.5 101t-113.5 38q-89 0 -173.5 -60t-149 -171t-97.5 -269l-101 -475h-168z" /> +<glyph unicode="o" horiz-adv-x="1149" d="M98 406q0 190 73 357.5t197 257t275 89.5q190 0 300 -112.5t110 -309.5q0 -188 -72 -355t-195 -258t-278 -91q-192 0 -301 113t-109 309zM270 397q0 -131 63.5 -202.5t182.5 -71.5q104 0 187 73t129.5 207.5t46.5 307.5q0 115 -62.5 186.5t-169.5 71.5q-109 0 -195.5 -74 t-134 -205.5t-47.5 -292.5z" /> +<glyph unicode="p" horiz-adv-x="1182" d="M-43 -492l336 1588h139l-26 -209h8q179 227 372 227q137 0 216 -97.5t79 -273.5q0 -212 -69 -389t-191 -275.5t-276 -98.5q-97 0 -170 50t-113 140h-10l-4 -38q-3 -25 -10.5 -70t-114.5 -554h-166zM319 346q0 -110 55.5 -168.5t160.5 -58.5q99 0 184.5 81t137.5 230.5 t52 317.5q0 227 -178 227q-96 0 -195.5 -95t-158 -239t-58.5 -295z" /> +<glyph unicode="q" horiz-adv-x="1182" d="M98 350q0 212 72.5 392t196 277t274.5 97q94 0 165.5 -50.5t108.5 -141.5h13l67 172h125l-336 -1588h-166l101 480q9 45 57 221h-8q-95 -121 -185 -175t-186 -54q-140 0 -219.5 97.5t-79.5 272.5zM270 346q0 -227 179 -227q92 0 190 92t158.5 237t60.5 300 q0 105 -54.5 166t-152.5 61q-101 0 -189 -84.5t-140 -233t-52 -311.5z" /> +<glyph unicode="r" horiz-adv-x="811" d="M59 0l234 1096h139l-22 -203h10q72 95 119 136.5t98.5 64t114.5 22.5q69 0 120 -14l-36 -150q-53 13 -105 13q-91 0 -170.5 -60t-139 -166.5t-87.5 -236.5l-107 -502h-168z" /> +<glyph unicode="s" horiz-adv-x="877" d="M8 49v158q70 -42 151 -65t150 -23q126 0 190 50t64 128q0 57 -35 96t-151 107q-130 73 -184 143t-54 166q0 138 101 222.5t266 84.5q171 0 330 -74l-54 -137l-56 25q-101 43 -220 43q-93 0 -146 -43.5t-53 -112.5q0 -56 35.5 -96t146.5 -103q107 -60 153.5 -103 t69.5 -92.5t23 -111.5q0 -156 -110.5 -243.5t-311.5 -87.5q-169 0 -305 69z" /> +<glyph unicode="t" horiz-adv-x="664" d="M90 969l14 73l185 78l125 228h98l-55 -252h274l-26 -127h-273l-129 -604q-18 -87 -18 -132q0 -56 29 -86t81 -30q55 0 144 26v-129q-34 -14 -84 -24t-80 -10q-125 0 -191.5 59.5t-66.5 177.5q0 66 18 150l127 602h-172z" /> +<glyph unicode="u" horiz-adv-x="1182" d="M113 248q0 62 22 172l146 676h170l-150 -695q-18 -89 -18 -139q0 -143 147 -143q88 0 173 60t150 172t99 270l100 475h166l-231 -1096h-139l22 203h-12q-98 -125 -187 -174t-184 -49q-128 0 -201 69.5t-73 198.5z" /> +<glyph unicode="v" horiz-adv-x="946" d="M98 1096h168l64 -613q24 -258 24 -362h6q127 275 179 371l325 604h178l-591 -1096h-228z" /> +<glyph unicode="w" horiz-adv-x="1468" d="M117 1096h164l18 -594v-88q0 -147 -8 -269h6q47 124 137 322l295 629h182l37 -594q6 -168 6 -262v-53l-2 -42h6q28 86 83 218.5t323 732.5h178l-506 -1096h-205l-32 602q-4 94 -4 172v156h-9l-50 -118l-83 -189l-291 -623h-202z" /> +<glyph unicode="x" horiz-adv-x="979" d="M-74 0l475 565l-239 531h170l174 -412l330 412h194l-455 -539l252 -557h-168l-192 434l-346 -434h-195z" /> +<glyph unicode="y" horiz-adv-x="946" d="M-197 -336q63 -18 131 -18q82 0 140.5 50.5t113.5 149.5l76 136l-166 1114h168l74 -545q10 -69 19.5 -203.5t9.5 -216.5h6q35 87 87 200t77 156l325 609h178l-696 -1282q-93 -172 -184 -239t-219 -67q-72 0 -140 21v135z" /> +<glyph unicode="z" horiz-adv-x="909" d="M-29 0l23 117l694 854h-479l27 125h657l-29 -140l-680 -831h531l-25 -125h-719z" /> +<glyph unicode="{" horiz-adv-x="715" d="M27 514l32 143q118 0 189.5 43.5t93.5 147.5l68 326q34 160 117.5 224t254.5 64h33l-31 -141q-105 0 -151 -36.5t-66 -123.5l-71 -321q-28 -123 -91 -184t-167 -78v-5q151 -41 151 -213q0 -59 -18 -131l-47 -211q-15 -58 -15 -98q0 -53 36.5 -77.5t119.5 -24.5v-142h-23 q-141 0 -216.5 52.5t-75.5 171.5q0 52 20 141q33 146 51.5 227.5t14.5 102.5q0 143 -209 143z" /> +<glyph unicode="|" d="M541 -496v2052h139v-2052h-139z" /> +<glyph unicode="}" horiz-adv-x="715" d="M-74 -182q115 0 167 36t71 123l72 322q25 117 88 179.5t170 80.5v6q-150 42 -150 211q0 59 18 131l50 213q14 65 14 99q0 53 -40.5 77.5t-139.5 24.5l28 141h11q144 0 220.5 -52.5t76.5 -170.5q0 -48 -21 -141l-49 -219q-16 -68 -16 -111q0 -143 209 -143l-33 -144 q-119 0 -190 -43t-93 -147l-67 -326q-36 -164 -119 -226.5t-264 -62.5h-13v142z" /> +<glyph unicode="~" d="M115 592v151q98 109 243 109q69 0 127 -14.5t144 -51.5q64 -27 112.5 -41t98.5 -14q55 0 119.5 33t115.5 88v-150q-100 -110 -244 -110q-72 0 -135 16.5t-135 48.5q-75 32 -120 44t-93 12q-54 0 -118.5 -34.5t-114.5 -86.5z" /> +<glyph unicode="&#xa1;" horiz-adv-x="530" d="M-14 -373l274 1057h109l-176 -1057h-207zM250 950q0 76 40.5 122t110.5 46q44 0 70.5 -26t26.5 -80q0 -71 -40.5 -117.5t-105.5 -46.5q-48 0 -75 25.5t-27 76.5z" /> +<glyph unicode="&#xa2;" d="M225 590q0 185 63.5 344t178.5 258.5t260 120.5l35 170h123l-37 -168q119 -9 217 -49l-47 -142q-109 52 -219 52q-112 0 -204.5 -76.5t-145 -213t-52.5 -296.5q0 -125 66 -198t184 -73q72 0 136 20t126 48v-143q-123 -62 -286 -66l-41 -198h-125l43 215 q-132 34 -203.5 137.5t-71.5 257.5z" /> +<glyph unicode="&#xa3;" d="M-23 0l27 141q205 46 258 289l47 221h-200l26 127h201l76 350q75 353 430 353q184 0 336 -86l-66 -133q-146 79 -278 79q-213 0 -263 -237l-69 -326h370l-26 -127h-371l-47 -219q-22 -98 -66 -166.5t-124 -111.5h725l-33 -154h-953z" /> +<glyph unicode="&#xa4;" d="M168 1067l92 92l127 -129q103 70 217 70t215 -70l129 129l92 -90l-129 -129q70 -104 70 -217q0 -119 -70 -217l127 -127l-90 -90l-129 127q-98 -68 -215 -68q-119 0 -217 70l-127 -127l-90 90l127 127q-68 96 -68 215q0 117 68 215zM358 723q0 -103 71.5 -174.5 t174.5 -71.5q104 0 177 71.5t73 174.5q0 104 -73 177t-177 73q-102 0 -174 -72.5t-72 -177.5z" /> +<glyph unicode="&#xa5;" d="M127 266l29 133h290l33 160h-291l29 133h225l-202 770h163l179 -747l491 747h187l-533 -770h231l-28 -133h-297l-33 -160h297l-29 -133h-295l-57 -266h-154l56 266h-291z" /> +<glyph unicode="&#xa6;" d="M541 281h139v-777h-139v777zM541 780v776h139v-776h-139z" /> +<glyph unicode="&#xa7;" horiz-adv-x="995" d="M59 53v148q56 -34 136.5 -56t156.5 -22q133 0 204 44.5t71 129.5q0 48 -50.5 89t-152.5 87q-138 61 -194 130.5t-56 166.5q0 201 238 307q-119 70 -119 203q0 127 103.5 206t279.5 79q189 0 321 -68l-53 -123q-148 60 -266 60q-102 0 -162.5 -40.5t-60.5 -109.5 q0 -49 38 -83.5t162 -90.5q100 -44 149 -83.5t75 -89.5t26 -114q0 -97 -61 -180t-172 -139q114 -71 114 -189q0 -152 -114 -237.5t-318 -85.5q-176 0 -295 61zM326 791q0 -70 50.5 -117t198.5 -111q80 44 127.5 107t47.5 131q0 60 -49.5 105.5t-186.5 103.5 q-82 -26 -135 -87.5t-53 -131.5z" /> +<glyph unicode="&#xa8;" horiz-adv-x="1135" d="M457 1378q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM821 1378q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="&#xa9;" horiz-adv-x="1704" d="M139 731q0 200 100 375t275 276t377 101q197 0 370 -97t277 -272t104 -383q0 -204 -100.5 -376.5t-273 -273.5t-377.5 -101q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM244 731q0 -173 87 -323.5t237.5 -237t322.5 -86.5q174 0 323 87t236.5 235.5t87.5 324.5 q0 174 -87 323t-235.5 236.5t-324.5 87.5q-174 0 -323 -87t-236.5 -235.5t-87.5 -324.5zM520 733q0 208 110 330.5t300 122.5q130 0 248 -60l-60 -120q-106 53 -190 53q-125 0 -191.5 -87t-66.5 -241q0 -169 65 -249.5t193 -80.5q82 0 211 43v-122q-66 -28 -113 -38 t-104 -10q-192 0 -297 119.5t-105 339.5z" /> +<glyph unicode="&#xaa;" horiz-adv-x="686" d="M170 1014q0 127 41.5 234.5t116.5 169t170 61.5q114 0 153 -103h6l37 90h86l-139 -665h-92l14 117h-4q-40 -56 -90 -93t-123 -37q-77 0 -126.5 60t-49.5 166zM283 1030q0 -139 98 -139q61 0 112.5 49t86 137.5t34.5 167.5q0 62 -28.5 96.5t-85.5 34.5q-92 0 -154.5 -103 t-62.5 -243z" /> +<glyph unicode="&#xab;" horiz-adv-x="958" d="M88 555v29l391 374l78 -81l-297 -328l172 -387l-113 -49zM483 510v31l367 405l86 -69l-283 -365l158 -350l-113 -49z" /> +<glyph unicode="&#xac;" d="M127 651v142h920v-529h-140v387h-780z" /> +<glyph unicode="&#xad;" horiz-adv-x="639" d="M55 469l35 158h479l-34 -158h-480z" /> +<glyph unicode="&#xae;" horiz-adv-x="1704" d="M139 731q0 200 100 375t275 276t377 101q197 0 370 -97t277 -272t104 -383q0 -204 -100.5 -376.5t-273 -273.5t-377.5 -101q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM244 731q0 -173 87 -323.5t237.5 -237t322.5 -86.5q174 0 323 87t236.5 235.5t87.5 324.5 q0 174 -87 323t-235.5 236.5t-324.5 87.5q-174 0 -323 -87t-236.5 -235.5t-87.5 -324.5zM645 291v880h229q163 0 241.5 -63t78.5 -193q0 -78 -47.5 -141t-132.5 -98l227 -385h-149l-207 352h-113v-352h-127zM772 762h92q195 0 195 149q0 76 -47.5 107t-149.5 31h-90v-287z " /> +<glyph unicode="&#xaf;" horiz-adv-x="782" d="M227 1556l33 132h787l-35 -132h-785z" /> +<glyph unicode="&#xb0;" horiz-adv-x="877" d="M215 1171q0 128 90.5 220t220.5 92q83 0 155.5 -41.5t114.5 -114t42 -156.5q0 -128 -90.5 -218.5t-221.5 -90.5t-221 90.5t-90 218.5zM328 1171q0 -80 58 -138t140 -58q83 0 140 58.5t57 137.5q0 82 -57.5 140.5t-139.5 58.5q-80 0 -139 -58.5t-59 -140.5z" /> +<glyph unicode="&#xb1;" d="M127 0v141h920v-141h-920zM127 643v141h389v392h141v-392h390v-141h-390v-387h-141v387h-389z" /> +<glyph unicode="&#xb2;" horiz-adv-x="717" d="M96 586l23 106l264 228q115 100 158.5 149.5t63.5 93t20 90.5q0 53 -31 85t-90 32q-90 0 -195 -80l-59 90q125 101 274 101q109 0 171.5 -56.5t62.5 -150.5q0 -99 -52.5 -179.5t-197.5 -205.5l-221 -187h395l-25 -116h-561z" /> +<glyph unicode="&#xb3;" horiz-adv-x="717" d="M119 625v127q125 -72 239 -72q205 0 205 170q0 137 -178 137h-90l22 107h95q97 0 155 41t58 112q0 60 -34.5 90.5t-93.5 30.5q-102 0 -196 -68l-55 93q109 88 268 88q114 0 178 -56t64 -151q0 -180 -207 -234v-4q69 -17 108 -68t39 -120q0 -132 -91 -205.5t-253 -73.5 q-125 0 -233 56z" /> +<glyph unicode="&#xb4;" horiz-adv-x="1135" d="M532 1241v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="&#xb5;" horiz-adv-x="1194" d="M-43 -492l336 1588h168l-148 -695q-18 -92 -18 -135q0 -147 147 -147q89 0 172 59t148.5 171t99.5 269l105 478h163l-233 -1096h-139l24 205h-12q-93 -121 -183 -173t-188 -52q-112 0 -163 96h-9q-11 -78 -22.5 -148t-83.5 -420h-164z" /> +<glyph unicode="&#xb6;" horiz-adv-x="1341" d="M199 1042q0 260 109 387t341 127h557v-1816h-114v1661h-213v-1661h-115v819q-62 -18 -146 -18q-216 0 -317.5 125t-101.5 376z" /> +<glyph unicode="&#xb7;" horiz-adv-x="518" d="M170 690q0 77 40.5 122.5t111.5 45.5q43 0 69.5 -26t26.5 -79q0 -71 -40 -118.5t-108 -47.5q-46 0 -73 26t-27 77z" /> +<glyph unicode="&#xb8;" horiz-adv-x="420" d="M-170 -383q38 -6 68 -6q174 0 174 110q0 46 -39 67.5t-99 29.5l101 182h106l-61 -121q131 -38 131 -155q0 -98 -81 -157t-214 -59q-41 0 -86 9v100z" /> +<glyph unicode="&#xb9;" horiz-adv-x="717" d="M258 1280l279 182h118l-186 -876h-135l112 526q25 103 58 225q-25 -25 -50 -46.5t-145 -100.5z" /> +<glyph unicode="&#xba;" horiz-adv-x="688" d="M168 1055q0 117 42 215.5t117.5 153.5t174.5 55q117 0 180 -67t63 -193q0 -191 -88.5 -311t-240.5 -120q-113 0 -180.5 71t-67.5 196zM281 1059q0 -85 38 -127.5t107 -42.5q94 0 152.5 88.5t58.5 232.5q0 166 -137 166q-102 0 -160.5 -87.5t-58.5 -229.5z" /> +<glyph unicode="&#xbb;" horiz-adv-x="958" d="M23 197l282 360l-158 354l113 50l217 -402v-31l-368 -401zM401 197l297 323l-172 391l113 50l233 -447v-29l-393 -370z" /> +<glyph unicode="&#xbc;" horiz-adv-x="1518" d="M123 0l1085 1462h154l-1086 -1462h-153zM204 1280l279 182h118l-186 -876h-135l112 526q25 103 58 225q-25 -25 -50 -46.5t-145 -100.5zM706 203l23 101l481 579h133l-121 -563h127l-22 -117h-129l-43 -202h-127l43 202h-365zM870 320h225q69 322 90 395 q-20 -36 -110 -149z" /> +<glyph unicode="&#xbd;" horiz-adv-x="1518" d="M148 1280l279 182h118l-186 -876h-135l112 526q25 103 58 225q-25 -25 -50 -46.5t-145 -100.5zM66 0l1085 1462h154l-1086 -1462h-153zM782 1l23 106l264 228q115 100 158.5 149.5t63.5 93t20 90.5q0 53 -31 85t-90 32q-90 0 -195 -80l-59 90q125 101 274 101 q109 0 171.5 -56.5t62.5 -150.5q0 -99 -52.5 -179.5t-197.5 -205.5l-221 -187h395l-25 -116h-561z" /> +<glyph unicode="&#xbe;" horiz-adv-x="1565" d="M87 625v127q125 -72 239 -72q205 0 205 170q0 137 -178 137h-90l22 107h95q97 0 155 41t58 112q0 60 -34.5 90.5t-93.5 30.5q-102 0 -196 -68l-55 93q109 88 268 88q114 0 178 -56t64 -151q0 -180 -207 -234v-4q69 -17 108 -68t39 -120q0 -132 -91 -205.5t-253 -73.5 q-125 0 -233 56zM273 0l1085 1462h154l-1086 -1462h-153zM856 203l23 101l481 579h133l-121 -563h127l-22 -117h-129l-43 -202h-127l43 202h-365zM1020 320h225q69 322 90 395q-20 -36 -110 -149z" /> +<glyph unicode="&#xbf;" horiz-adv-x="874" d="M-4 -78q0 124 66 228t225 223q132 98 172.5 152.5t62.5 154.5h135q-22 -130 -72 -212t-165 -175l-95 -75q-159 -127 -159 -275q0 -93 51.5 -144t147.5 -51q80 0 154 25.5t140 56.5l62 -129q-90 -48 -189 -74t-186 -26q-168 0 -259 83.5t-91 237.5zM512 946q0 71 40 118.5 t107 47.5q47 0 74 -25.5t27 -76.5q0 -77 -40.5 -122.5t-111.5 -45.5q-43 0 -69.5 26t-26.5 78z" /> +<glyph unicode="&#xc0;" horiz-adv-x="1137" d="M-117 0l799 1462h174l184 -1462h-170l-57 465h-496l-245 -465h-189zM401 621h394l-35 299q-24 179 -29 350q-37 -88 -80.5 -175t-249.5 -474zM535 1886v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="&#xc1;" horiz-adv-x="1137" d="M-117 0l799 1462h174l184 -1462h-170l-57 465h-496l-245 -465h-189zM401 621h394l-35 299q-24 179 -29 350q-37 -88 -80.5 -175t-249.5 -474zM679 1579v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="&#xc2;" horiz-adv-x="1137" d="M-117 0l799 1462h174l184 -1462h-170l-57 465h-496l-245 -465h-189zM401 621h394l-35 299q-24 179 -29 350q-37 -88 -80.5 -175t-249.5 -474zM465 1579v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189 h-109z" /> +<glyph unicode="&#xc3;" horiz-adv-x="1137" d="M-117 0l799 1462h174l184 -1462h-170l-57 465h-496l-245 -465h-189zM401 621h394l-35 299q-24 179 -29 350q-37 -88 -80.5 -175t-249.5 -474zM432 1579q58 258 231 258q44 0 83.5 -18t75 -39.5t66.5 -39.5t58 -18q44 0 69.5 27t51.5 90h100q-66 -258 -233 -258 q-40 0 -77.5 17.5t-73 39t-69 39t-65.5 17.5q-44 0 -69.5 -28.5t-47.5 -86.5h-100z" /> +<glyph unicode="&#xc4;" horiz-adv-x="1137" d="M-117 0l799 1462h174l184 -1462h-170l-57 465h-496l-245 -465h-189zM401 621h394l-35 299q-24 179 -29 350q-37 -88 -80.5 -175t-249.5 -474zM523 1716q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM887 1716q0 46 28 79.5 t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="&#xc5;" horiz-adv-x="1137" d="M-117 0l799 1462h174l184 -1462h-170l-57 465h-496l-245 -465h-189zM401 621h394l-35 299q-24 179 -29 350q-37 -88 -80.5 -175t-249.5 -474zM553 1583q0 94 62 152.5t157 58.5q101 0 160 -57t59 -152q0 -99 -60 -157t-159 -58q-101 0 -160 57.5t-59 155.5zM657 1583 q0 -54 29.5 -84.5t85.5 -30.5q51 0 83 30.5t32 84.5q0 53 -32 84t-83 31q-49 0 -82 -31t-33 -84z" /> +<glyph unicode="&#xc6;" horiz-adv-x="1673" d="M-119 0l938 1462h938l-33 -153h-565l-100 -469h528l-28 -150h-529l-115 -538h566l-33 -152h-737l98 465h-438l-293 -465h-197zM469 621h371l147 688h-84z" /> +<glyph unicode="&#xc7;" horiz-adv-x="1198" d="M150 537q0 261 105.5 485.5t283.5 342.5t403 118q197 0 348 -80l-69 -141q-138 69 -279 69q-174 0 -311.5 -97t-218 -284.5t-80.5 -408.5q0 -187 97.5 -298.5t268.5 -111.5q139 0 322 57v-149q-86 -31 -164 -45t-188 -14q-242 0 -380 149.5t-138 407.5zM377 -383 q38 -6 68 -6q174 0 174 110q0 46 -39 67.5t-99 29.5l101 182h106l-61 -121q131 -38 131 -155q0 -98 -81 -157t-214 -59q-41 0 -86 9v100z" /> +<glyph unicode="&#xc8;" horiz-adv-x="1047" d="M86 0l309 1462h735l-32 -153h-566l-98 -469h527l-29 -152h-529l-114 -536h565l-33 -152h-735zM570 1886v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="&#xc9;" horiz-adv-x="1047" d="M86 0l309 1462h735l-32 -153h-566l-98 -469h527l-29 -152h-529l-114 -536h565l-33 -152h-735zM657 1579v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="&#xca;" horiz-adv-x="1047" d="M86 0l309 1462h735l-32 -153h-566l-98 -469h527l-29 -152h-529l-114 -536h565l-33 -152h-735zM469 1579v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="&#xcb;" horiz-adv-x="1047" d="M86 0l309 1462h735l-32 -153h-566l-98 -469h527l-29 -152h-529l-114 -536h565l-33 -152h-735zM523 1716q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM887 1716q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34 q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="&#xcc;" horiz-adv-x="559" d="M86 0l311 1462h168l-311 -1462h-168zM265 1886v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="&#xcd;" horiz-adv-x="559" d="M86 0l311 1462h168l-311 -1462h-168zM412 1579v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="&#xce;" horiz-adv-x="559" d="M86 0l311 1462h168l-311 -1462h-168zM193 1579v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="&#xcf;" horiz-adv-x="559" d="M86 0l311 1462h168l-311 -1462h-168zM265 1716q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM629 1716q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="&#xd0;" horiz-adv-x="1364" d="M72 649l32 150h150l141 663h342q276 0 419.5 -149.5t143.5 -435.5q0 -261 -105 -461t-300 -308t-457 -108h-352l135 649h-149zM287 147h162q202 0 355 91.5t234.5 258.5t81.5 382t-103 325.5t-302 110.5h-178l-111 -516h330l-33 -150h-330z" /> +<glyph unicode="&#xd1;" horiz-adv-x="1438" d="M84 0l309 1462h180l459 -1220h6q30 224 72 405l174 815h164l-309 -1462h-181l-460 1223h-6q-32 -221 -74 -418l-172 -805h-162zM600 1579q58 258 231 258q44 0 83.5 -18t75 -39.5t66.5 -39.5t58 -18q44 0 69.5 27t51.5 90h100q-66 -258 -233 -258q-40 0 -77.5 17.5 t-73 39t-69 39t-65.5 17.5q-44 0 -69.5 -28.5t-47.5 -86.5h-100z" /> +<glyph unicode="&#xd2;" horiz-adv-x="1475" d="M150 549q0 264 96 482t263.5 336t377.5 118q244 0 384 -154t140 -424q0 -269 -88 -481.5t-252 -329t-379 -116.5q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q152 0 272.5 97.5t190.5 279.5t70 403q0 199 -94 310.5t-261 111.5q-157 0 -281 -101 t-192.5 -281t-68.5 -398zM679 1886v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="&#xd3;" horiz-adv-x="1475" d="M150 549q0 264 96 482t263.5 336t377.5 118q244 0 384 -154t140 -424q0 -269 -88 -481.5t-252 -329t-379 -116.5q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q152 0 272.5 97.5t190.5 279.5t70 403q0 199 -94 310.5t-261 111.5q-157 0 -281 -101 t-192.5 -281t-68.5 -398zM821 1579v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="&#xd4;" horiz-adv-x="1475" d="M150 549q0 264 96 482t263.5 336t377.5 118q244 0 384 -154t140 -424q0 -269 -88 -481.5t-252 -329t-379 -116.5q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q152 0 272.5 97.5t190.5 279.5t70 403q0 199 -94 310.5t-261 111.5q-157 0 -281 -101 t-192.5 -281t-68.5 -398zM612 1579v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="&#xd5;" horiz-adv-x="1475" d="M150 549q0 264 96 482t263.5 336t377.5 118q244 0 384 -154t140 -424q0 -269 -88 -481.5t-252 -329t-379 -116.5q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q152 0 272.5 97.5t190.5 279.5t70 403q0 199 -94 310.5t-261 111.5q-157 0 -281 -101 t-192.5 -281t-68.5 -398zM565 1579q58 258 231 258q44 0 83.5 -18t75 -39.5t66.5 -39.5t58 -18q44 0 69.5 27t51.5 90h100q-66 -258 -233 -258q-40 0 -77.5 17.5t-73 39t-69 39t-65.5 17.5q-44 0 -69.5 -28.5t-47.5 -86.5h-100z" /> +<glyph unicode="&#xd6;" horiz-adv-x="1475" d="M150 549q0 264 96 482t263.5 336t377.5 118q244 0 384 -154t140 -424q0 -269 -88 -481.5t-252 -329t-379 -116.5q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q152 0 272.5 97.5t190.5 279.5t70 403q0 199 -94 310.5t-261 111.5q-157 0 -281 -101 t-192.5 -281t-68.5 -398zM664 1716q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM1028 1716q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="&#xd7;" d="M168 1044l98 99l320 -320l323 320l99 -96l-324 -324l322 -322l-97 -96l-323 320l-320 -318l-96 96l317 320z" /> +<glyph unicode="&#xd8;" horiz-adv-x="1475" d="M119 8l137 170q-106 136 -106 371q0 264 96 482t263.5 336t377.5 118q99 0 178.5 -27t151.5 -84l131 166l114 -92l-149 -184q48 -62 73 -156t25 -201q0 -269 -88 -481.5t-252 -329t-379 -116.5q-200 0 -332 96l-129 -160zM332 553q0 -135 41 -227l737 919q-90 88 -236 88 q-157 0 -281 -101t-192.5 -281t-68.5 -398zM463 205q91 -74 233 -74q152 0 272.5 97.5t190.5 279.5t70 403q0 118 -33 205z" /> +<glyph unicode="&#xd9;" horiz-adv-x="1384" d="M164 383q0 81 24 201l189 878h170l-191 -891q-22 -106 -22 -188q0 -117 73 -184.5t218 -67.5q172 0 267.5 87.5t139.5 289.5l205 954h170l-205 -966q-55 -263 -197.5 -389.5t-388.5 -126.5q-230 0 -341 104t-111 299zM663 1886v21h181q43 -136 147 -303v-25h-104 q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="&#xda;" horiz-adv-x="1384" d="M164 383q0 81 24 201l189 878h170l-191 -891q-22 -106 -22 -188q0 -117 73 -184.5t218 -67.5q172 0 267.5 87.5t139.5 289.5l205 954h170l-205 -966q-55 -263 -197.5 -389.5t-388.5 -126.5q-230 0 -341 104t-111 299zM823 1579v27q56 60 125.5 151.5t106.5 149.5h190v-21 q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="&#xdb;" horiz-adv-x="1384" d="M164 383q0 81 24 201l189 878h170l-191 -891q-22 -106 -22 -188q0 -117 73 -184.5t218 -67.5q172 0 267.5 87.5t139.5 289.5l205 954h170l-205 -966q-55 -263 -197.5 -389.5t-388.5 -126.5q-230 0 -341 104t-111 299zM602 1579v27q145 133 204.5 197.5t82.5 103.5h158 q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="&#xdc;" horiz-adv-x="1384" d="M164 383q0 81 24 201l189 878h170l-191 -891q-22 -106 -22 -188q0 -117 73 -184.5t218 -67.5q172 0 267.5 87.5t139.5 289.5l205 954h170l-205 -966q-55 -263 -197.5 -389.5t-388.5 -126.5q-230 0 -341 104t-111 299zM643 1716q0 46 28 79.5t74 33.5q78 0 78 -80 q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM1007 1716q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="&#xdd;" horiz-adv-x="1030" d="M188 1462h170l179 -747l489 747h193l-627 -921l-113 -541h-172l119 549zM616 1579v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="&#xde;" horiz-adv-x="1159" d="M86 0l309 1462h170l-53 -256h160q213 0 323.5 -95t110.5 -282q0 -248 -164 -379t-483 -131h-133l-70 -319h-170zM354 465h135q215 0 328 91t113 267q0 126 -70 181t-215 55h-166z" /> +<glyph unicode="&#xdf;" horiz-adv-x="1182" d="M-256 -328q61 -22 111 -22q65 0 107 47.5t65 157.5l280 1314q43 200 156 299t307 99q162 0 252 -71t90 -196q0 -57 -21 -106.5t-61.5 -95t-178.5 -150.5q-110 -83 -110 -151q0 -56 95 -122q47 -34 101 -87.5t79.5 -110t25.5 -123.5q0 -175 -108.5 -274.5t-292.5 -99.5 q-175 0 -268 71v160q51 -41 118.5 -66.5t129.5 -25.5q113 0 181 58t68 159q0 40 -10.5 71t-33.5 59t-89 83q-88 69 -122.5 124t-34.5 115q0 53 18.5 96t49.5 78.5t124 104.5q80 56 111 87.5t48 65t17 70.5q0 64 -52.5 100.5t-141.5 36.5q-119 0 -186 -62.5t-95 -190.5 l-274 -1303q-40 -189 -121 -276t-211 -87q-69 0 -123 21v143z" /> +<glyph unicode="&#xe0;" horiz-adv-x="1157" d="M98 350q0 208 71 386t196 279t274 101q92 0 164 -49.5t112 -142.5h11l67 172h127l-233 -1096h-133l26 209h-8q-179 -229 -377 -229q-139 0 -218 99t-79 271zM270 346q0 -114 47 -170.5t132 -56.5q97 0 193 92.5t156 241t60 297.5q0 103 -56 164t-147 61 q-104 0 -193.5 -86t-140.5 -233t-51 -310zM496 1548v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="&#xe1;" horiz-adv-x="1157" d="M98 350q0 208 71 386t196 279t274 101q92 0 164 -49.5t112 -142.5h11l67 172h127l-233 -1096h-133l26 209h-8q-179 -229 -377 -229q-139 0 -218 99t-79 271zM270 346q0 -114 47 -170.5t132 -56.5q97 0 193 92.5t156 241t60 297.5q0 103 -56 164t-147 61 q-104 0 -193.5 -86t-140.5 -233t-51 -310zM600 1241v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="&#xe2;" horiz-adv-x="1157" d="M98 350q0 208 71 386t196 279t274 101q92 0 164 -49.5t112 -142.5h11l67 172h127l-233 -1096h-133l26 209h-8q-179 -229 -377 -229q-139 0 -218 99t-79 271zM270 346q0 -114 47 -170.5t132 -56.5q97 0 193 92.5t156 241t60 297.5q0 103 -56 164t-147 61 q-104 0 -193.5 -86t-140.5 -233t-51 -310zM390 1241v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="&#xe3;" horiz-adv-x="1157" d="M98 350q0 208 71 386t196 279t274 101q92 0 164 -49.5t112 -142.5h11l67 172h127l-233 -1096h-133l26 209h-8q-179 -229 -377 -229q-139 0 -218 99t-79 271zM270 346q0 -114 47 -170.5t132 -56.5q97 0 193 92.5t156 241t60 297.5q0 103 -56 164t-147 61 q-104 0 -193.5 -86t-140.5 -233t-51 -310zM354 1241q58 258 231 258q44 0 83.5 -18t75 -39.5t66.5 -39.5t58 -18q44 0 69.5 27t51.5 90h100q-66 -258 -233 -258q-40 0 -77.5 17.5t-73 39t-69 39t-65.5 17.5q-44 0 -69.5 -28.5t-47.5 -86.5h-100z" /> +<glyph unicode="&#xe4;" horiz-adv-x="1157" d="M98 350q0 208 71 386t196 279t274 101q92 0 164 -49.5t112 -142.5h11l67 172h127l-233 -1096h-133l26 209h-8q-179 -229 -377 -229q-139 0 -218 99t-79 271zM270 346q0 -114 47 -170.5t132 -56.5q97 0 193 92.5t156 241t60 297.5q0 103 -56 164t-147 61 q-104 0 -193.5 -86t-140.5 -233t-51 -310zM454 1378q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM818 1378q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="&#xe5;" horiz-adv-x="1157" d="M98 350q0 208 71 386t196 279t274 101q92 0 164 -49.5t112 -142.5h11l67 172h127l-233 -1096h-133l26 209h-8q-179 -229 -377 -229q-139 0 -218 99t-79 271zM270 346q0 -114 47 -170.5t132 -56.5q97 0 193 92.5t156 241t60 297.5q0 103 -56 164t-147 61 q-104 0 -193.5 -86t-140.5 -233t-51 -310zM513 1454q0 94 62 152.5t157 58.5q101 0 160 -57t59 -152q0 -99 -60 -157t-159 -58q-101 0 -160 57.5t-59 155.5zM617 1454q0 -54 29.5 -84.5t85.5 -30.5q51 0 83 30.5t32 84.5q0 53 -32 84t-83 31q-49 0 -82 -31t-33 -84z" /> +<glyph unicode="&#xe6;" horiz-adv-x="1669" d="M98 348q0 206 70.5 385t191.5 281t263 102q82 0 145 -48.5t102 -143.5h11l67 172h109l-31 -146q123 166 332 166q119 0 192.5 -68t73.5 -184q0 -182 -166.5 -283.5t-472.5 -101.5h-39l-4 -80q0 -131 62.5 -204.5t193.5 -73.5q55 0 116.5 16.5t178.5 67.5v-150 q-164 -75 -328 -75q-108 0 -189.5 39.5t-121.5 119.5l-31 -139h-114l26 209h-8q-109 -132 -191.5 -180.5t-177.5 -48.5q-122 0 -191 99t-69 269zM270 348q0 -114 37 -171.5t105 -57.5q95 0 188.5 91.5t153 240.5t59.5 299q0 103 -45.5 164t-122.5 61q-99 0 -187 -86.5 t-138 -231.5t-50 -309zM973 618h14q226 0 348.5 58.5t122.5 169.5q0 61 -35 94t-98 33q-117 0 -211 -94.5t-141 -260.5z" /> +<glyph unicode="&#xe7;" horiz-adv-x="922" d="M98 389q0 200 74 369t204.5 263.5t293.5 94.5q137 0 268 -51l-47 -141q-120 51 -219 51q-112 0 -204.5 -76.5t-145 -213t-52.5 -296.5q0 -128 66.5 -199t183.5 -71q72 0 136 20t126 47v-143q-124 -63 -276 -63q-194 0 -301 107t-107 302zM211 -383q38 -6 68 -6 q174 0 174 110q0 46 -39 67.5t-99 29.5l101 182h106l-61 -121q131 -38 131 -155q0 -98 -81 -157t-214 -59q-41 0 -86 9v100z" /> +<glyph unicode="&#xe8;" horiz-adv-x="1010" d="M98 391q0 188 74.5 360.5t197.5 268.5t271 96q153 0 230 -66.5t77 -185.5q0 -180 -166 -282.5t-475 -102.5h-33l-4 -80q0 -131 61.5 -204.5t190.5 -73.5q63 0 129.5 18t165.5 66v-146q-94 -44 -166 -61.5t-159 -17.5q-184 0 -289 109t-105 302zM299 618h12 q228 0 349.5 59.5t121.5 172.5q0 53 -36.5 88t-114.5 35q-103 0 -193.5 -94t-138.5 -261zM449 1548v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="&#xe9;" horiz-adv-x="1010" d="M98 391q0 188 74.5 360.5t197.5 268.5t271 96q153 0 230 -66.5t77 -185.5q0 -180 -166 -282.5t-475 -102.5h-33l-4 -80q0 -131 61.5 -204.5t190.5 -73.5q63 0 129.5 18t165.5 66v-146q-94 -44 -166 -61.5t-159 -17.5q-184 0 -289 109t-105 302zM299 618h12 q228 0 349.5 59.5t121.5 172.5q0 53 -36.5 88t-114.5 35q-103 0 -193.5 -94t-138.5 -261zM585 1241v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="&#xea;" horiz-adv-x="1010" d="M98 391q0 188 74.5 360.5t197.5 268.5t271 96q153 0 230 -66.5t77 -185.5q0 -180 -166 -282.5t-475 -102.5h-33l-4 -80q0 -131 61.5 -204.5t190.5 -73.5q63 0 129.5 18t165.5 66v-146q-94 -44 -166 -61.5t-159 -17.5q-184 0 -289 109t-105 302zM299 618h12 q228 0 349.5 59.5t121.5 172.5q0 53 -36.5 88t-114.5 35q-103 0 -193.5 -94t-138.5 -261zM351 1241v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="&#xeb;" horiz-adv-x="1010" d="M98 391q0 188 74.5 360.5t197.5 268.5t271 96q153 0 230 -66.5t77 -185.5q0 -180 -166 -282.5t-475 -102.5h-33l-4 -80q0 -131 61.5 -204.5t190.5 -73.5q63 0 129.5 18t165.5 66v-146q-94 -44 -166 -61.5t-159 -17.5q-184 0 -289 109t-105 302zM299 618h12 q228 0 349.5 59.5t121.5 172.5q0 53 -36.5 88t-114.5 35q-103 0 -193.5 -94t-138.5 -261zM413 1378q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM777 1378q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34 q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="&#xec;" horiz-adv-x="520" d="M59 0l234 1096h168l-234 -1096h-168zM164 1548v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="&#xed;" horiz-adv-x="520" d="M59 0l234 1096h168l-234 -1096h-168zM324 1241v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="&#xee;" horiz-adv-x="520" d="M59 0l234 1096h168l-234 -1096h-168zM93 1241v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="&#xef;" horiz-adv-x="520" d="M59 0l234 1096h168l-234 -1096h-168zM161 1378q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM525 1378q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="&#xf0;" horiz-adv-x="1165" d="M90 373q0 160 67.5 298t187 217t267.5 79q105 0 181.5 -45.5t111.5 -124.5l6 2v17q0 136 -36.5 240t-110.5 197l-270 -149l-56 108l238 131q-66 58 -146 113l95 117q118 -84 188 -154l260 146l64 -105l-240 -133q87 -115 126.5 -240.5t39.5 -269.5q0 -253 -71.5 -447 t-203 -292t-311.5 -98q-182 0 -284.5 104t-102.5 289zM262 377q0 -126 57.5 -191t167.5 -65q107 0 190 56t134 168t51 226q0 118 -65.5 187t-178.5 69q-109 0 -189 -57.5t-123.5 -161t-43.5 -231.5z" /> +<glyph unicode="&#xf1;" horiz-adv-x="1182" d="M59 0l234 1096h139l-22 -203h10q96 122 185.5 172.5t185.5 50.5q127 0 200.5 -69.5t73.5 -194.5q0 -79 -23 -180l-143 -672h-170l148 692q20 104 20 144q0 63 -35.5 101t-113.5 38q-89 0 -173.5 -60t-149 -171t-97.5 -269l-101 -475h-168zM369 1241q58 258 231 258 q44 0 83.5 -18t75 -39.5t66.5 -39.5t58 -18q44 0 69.5 27t51.5 90h100q-66 -258 -233 -258q-40 0 -77.5 17.5t-73 39t-69 39t-65.5 17.5q-44 0 -69.5 -28.5t-47.5 -86.5h-100z" /> +<glyph unicode="&#xf2;" horiz-adv-x="1149" d="M98 406q0 190 73 357.5t197 257t275 89.5q190 0 300 -112.5t110 -309.5q0 -188 -72 -355t-195 -258t-278 -91q-192 0 -301 113t-109 309zM270 397q0 -131 63.5 -202.5t182.5 -71.5q104 0 187 73t129.5 207.5t46.5 307.5q0 115 -62.5 186.5t-169.5 71.5q-109 0 -195.5 -74 t-134 -205.5t-47.5 -292.5zM470 1548v21h181q43 -136 147 -303v-25h-104q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="&#xf3;" horiz-adv-x="1149" d="M98 406q0 190 73 357.5t197 257t275 89.5q190 0 300 -112.5t110 -309.5q0 -188 -72 -355t-195 -258t-278 -91q-192 0 -301 113t-109 309zM270 397q0 -131 63.5 -202.5t182.5 -71.5q104 0 187 73t129.5 207.5t46.5 307.5q0 115 -62.5 186.5t-169.5 71.5q-109 0 -195.5 -74 t-134 -205.5t-47.5 -292.5zM589 1241v27q56 60 125.5 151.5t106.5 149.5h190v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="&#xf4;" horiz-adv-x="1149" d="M98 406q0 190 73 357.5t197 257t275 89.5q190 0 300 -112.5t110 -309.5q0 -188 -72 -355t-195 -258t-278 -91q-192 0 -301 113t-109 309zM270 397q0 -131 63.5 -202.5t182.5 -71.5q104 0 187 73t129.5 207.5t46.5 307.5q0 115 -62.5 186.5t-169.5 71.5q-109 0 -195.5 -74 t-134 -205.5t-47.5 -292.5zM382 1241v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="&#xf5;" horiz-adv-x="1149" d="M98 406q0 190 73 357.5t197 257t275 89.5q190 0 300 -112.5t110 -309.5q0 -188 -72 -355t-195 -258t-278 -91q-192 0 -301 113t-109 309zM270 397q0 -131 63.5 -202.5t182.5 -71.5q104 0 187 73t129.5 207.5t46.5 307.5q0 115 -62.5 186.5t-169.5 71.5q-109 0 -195.5 -74 t-134 -205.5t-47.5 -292.5zM342 1241q58 258 231 258q44 0 83.5 -18t75 -39.5t66.5 -39.5t58 -18q44 0 69.5 27t51.5 90h100q-66 -258 -233 -258q-40 0 -77.5 17.5t-73 39t-69 39t-65.5 17.5q-44 0 -69.5 -28.5t-47.5 -86.5h-100z" /> +<glyph unicode="&#xf6;" horiz-adv-x="1149" d="M98 406q0 190 73 357.5t197 257t275 89.5q190 0 300 -112.5t110 -309.5q0 -188 -72 -355t-195 -258t-278 -91q-192 0 -301 113t-109 309zM270 397q0 -131 63.5 -202.5t182.5 -71.5q104 0 187 73t129.5 207.5t46.5 307.5q0 115 -62.5 186.5t-169.5 71.5q-109 0 -195.5 -74 t-134 -205.5t-47.5 -292.5zM433 1378q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM797 1378q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="&#xf7;" d="M127 651v142h920v-142h-920zM475 373q0 121 111 121q53 0 82.5 -30.5t29.5 -90.5q0 -58 -30 -89.5t-82 -31.5t-81.5 31t-29.5 90zM475 1071q0 121 111 121q53 0 82.5 -30.5t29.5 -90.5q0 -58 -30 -89.5t-82 -31.5t-81.5 31t-29.5 90z" /> +<glyph unicode="&#xf8;" horiz-adv-x="1149" d="M61 6l109 135q-68 103 -68 265q0 194 73.5 361t195.5 255t272 88q146 0 252 -68l104 129l105 -79l-119 -129q62 -97 62 -258q0 -189 -69.5 -360t-191.5 -266t-276 -95q-146 0 -246 65l-98 -125zM264 416q0 -92 17 -137l518 645q-54 47 -152 47q-108 0 -195.5 -73 t-137.5 -202t-50 -280zM358 166q57 -45 158 -45q103 0 188.5 71.5t133 200.5t47.5 295q0 84 -13 119z" /> +<glyph unicode="&#xf9;" horiz-adv-x="1182" d="M113 248q0 62 22 172l146 676h170l-150 -695q-18 -89 -18 -139q0 -143 147 -143q88 0 173 60t150 172t99 270l100 475h166l-231 -1096h-139l22 203h-12q-98 -125 -187 -174t-184 -49q-128 0 -201 69.5t-73 198.5zM472 1548v21h181q43 -136 147 -303v-25h-104 q-61 61 -128.5 154t-95.5 153z" /> +<glyph unicode="&#xfa;" horiz-adv-x="1182" d="M113 248q0 62 22 172l146 676h170l-150 -695q-18 -89 -18 -139q0 -143 147 -143q88 0 173 60t150 172t99 270l100 475h166l-231 -1096h-139l22 203h-12q-98 -125 -187 -174t-184 -49q-128 0 -201 69.5t-73 198.5zM636 1241v27q56 60 125.5 151.5t106.5 149.5h190v-21 q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="&#xfb;" horiz-adv-x="1182" d="M113 248q0 62 22 172l146 676h170l-150 -695q-18 -89 -18 -139q0 -143 147 -143q88 0 173 60t150 172t99 270l100 475h166l-231 -1096h-139l22 203h-12q-98 -125 -187 -174t-184 -49q-128 0 -201 69.5t-73 198.5zM409 1241v27q145 133 204.5 197.5t82.5 103.5h158 q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="&#xfc;" horiz-adv-x="1182" d="M113 248q0 62 22 172l146 676h170l-150 -695q-18 -89 -18 -139q0 -143 147 -143q88 0 173 60t150 172t99 270l100 475h166l-231 -1096h-139l22 203h-12q-98 -125 -187 -174t-184 -49q-128 0 -201 69.5t-73 198.5zM457 1378q0 46 28 79.5t74 33.5q78 0 78 -80 q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM821 1378q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="&#xfd;" horiz-adv-x="946" d="M-197 -336q63 -18 131 -18q82 0 140.5 50.5t113.5 149.5l76 136l-166 1114h168l74 -545q10 -69 19.5 -203.5t9.5 -216.5h6q35 87 87 200t77 156l325 609h178l-696 -1282q-93 -172 -184 -239t-219 -67q-72 0 -140 21v135zM500 1241v27q56 60 125.5 151.5t106.5 149.5h190 v-21q-38 -49 -140 -151t-177 -156h-105z" /> +<glyph unicode="&#xfe;" horiz-adv-x="1182" d="M-43 -492l432 2048h168q-95 -441 -115 -522t-39 -149h9q101 125 189 177t183 52q139 0 218 -97.5t79 -273.5q0 -212 -69 -389t-191 -275.5t-276 -98.5q-98 0 -172 51t-113 139h-10q-8 -104 -25 -176l-102 -486h-166zM319 346q0 -110 55.5 -168.5t160.5 -58.5 q99 0 184.5 81t137.5 230.5t52 317.5q0 227 -178 227q-96 0 -195.5 -95t-158 -239t-58.5 -295z" /> +<glyph unicode="&#xff;" horiz-adv-x="946" d="M-197 -336q63 -18 131 -18q82 0 140.5 50.5t113.5 149.5l76 136l-166 1114h168l74 -545q10 -69 19.5 -203.5t9.5 -216.5h6q35 87 87 200t77 156l325 609h178l-696 -1282q-93 -172 -184 -239t-219 -67q-72 0 -140 21v135zM335 1378q0 46 28 79.5t74 33.5q78 0 78 -80 q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM699 1378q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62z" /> +<glyph unicode="&#x131;" horiz-adv-x="520" d="M59 0l234 1096h168l-234 -1096h-168z" /> +<glyph unicode="&#x152;" horiz-adv-x="1751" d="M150 549q0 264 96 482t263.5 336t377.5 118q152 0 237 -23h709l-31 -153h-565l-100 -469h528l-31 -150h-528l-115 -538h565l-32 -152h-674q-78 -20 -158 -20q-256 0 -399 149.5t-143 419.5zM332 553q0 -199 98 -310.5t266 -111.5q69 0 123 19l246 1161q-76 22 -191 22 q-157 0 -281 -101t-192.5 -281t-68.5 -398z" /> +<glyph unicode="&#x153;" horiz-adv-x="1769" d="M98 406q0 193 75 360t201 255.5t281 88.5q270 0 359 -225q75 109 177.5 170t221.5 61q139 0 217 -65.5t78 -186.5q0 -183 -164.5 -284t-468.5 -101h-41l-4 -80q0 -131 61.5 -204.5t190.5 -73.5q75 0 145 24.5t150 59.5v-150q-162 -75 -326 -75q-270 0 -356 225 q-69 -107 -171.5 -164t-225.5 -57q-184 0 -292 114t-108 308zM270 410q0 -141 62 -214t172 -73q177 0 278 160.5t101 427.5q0 124 -59.5 191t-174.5 67q-109 0 -196 -73t-135 -202t-48 -284zM1053 618h18q231 0 351 61t120 177q0 48 -32 82.5t-97 34.5q-125 0 -220.5 -94.5 t-139.5 -260.5z" /> +<glyph unicode="&#x178;" horiz-adv-x="1030" d="M188 1462h170l179 -747l489 747h193l-627 -921l-113 -541h-172l119 549zM452 1716q0 46 28 79.5t74 33.5q78 0 78 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22t-23.5 62zM816 1716q0 46 28 79.5t75 33.5q77 0 77 -80q0 -49 -29.5 -83t-68.5 -34q-35 0 -58.5 22 t-23.5 62z" /> +<glyph unicode="&#x2c6;" horiz-adv-x="1135" d="M399 1241v27q145 133 204.5 197.5t82.5 103.5h158q37 -99 128 -235l42 -66v-27h-103q-57 48 -161 189q-134 -119 -242 -189h-109z" /> +<glyph unicode="&#x2da;" horiz-adv-x="1182" d="M551 1454q0 94 62 152.5t157 58.5q101 0 160 -57t59 -152q0 -99 -60 -157t-159 -58q-101 0 -160 57.5t-59 155.5zM655 1454q0 -54 29.5 -84.5t85.5 -30.5q51 0 83 30.5t32 84.5q0 53 -32 84t-83 31q-49 0 -82 -31t-33 -84z" /> +<glyph unicode="&#x2dc;" horiz-adv-x="1135" d="M336 1241q58 258 231 258q44 0 83.5 -18t75 -39.5t66.5 -39.5t58 -18q44 0 69.5 27t51.5 90h100q-66 -258 -233 -258q-40 0 -77.5 17.5t-73 39t-69 39t-65.5 17.5q-44 0 -69.5 -28.5t-47.5 -86.5h-100z" /> +<glyph unicode="&#x2000;" horiz-adv-x="953" /> +<glyph unicode="&#x2001;" horiz-adv-x="1907" /> +<glyph unicode="&#x2002;" horiz-adv-x="953" /> +<glyph unicode="&#x2003;" horiz-adv-x="1907" /> +<glyph unicode="&#x2004;" horiz-adv-x="635" /> +<glyph unicode="&#x2005;" horiz-adv-x="476" /> +<glyph unicode="&#x2006;" horiz-adv-x="317" /> +<glyph unicode="&#x2007;" horiz-adv-x="317" /> +<glyph unicode="&#x2008;" horiz-adv-x="238" /> +<glyph unicode="&#x2009;" horiz-adv-x="381" /> +<glyph unicode="&#x200a;" horiz-adv-x="105" /> +<glyph unicode="&#x2010;" horiz-adv-x="639" d="M55 469l35 158h479l-34 -158h-480z" /> +<glyph unicode="&#x2011;" horiz-adv-x="639" d="M55 469l35 158h479l-34 -158h-480z" /> +<glyph unicode="&#x2012;" horiz-adv-x="639" d="M55 469l35 158h479l-34 -158h-480z" /> +<glyph unicode="&#x2013;" horiz-adv-x="983" d="M55 469l35 160h823l-34 -160h-824z" /> +<glyph unicode="&#x2014;" horiz-adv-x="1966" d="M55 469l35 160h1806l-34 -160h-1807z" /> +<glyph unicode="&#x2018;" horiz-adv-x="348" d="M123 983q98 211 270 479h127q-147 -345 -203 -501h-188z" /> +<glyph unicode="&#x2019;" horiz-adv-x="348" d="M125 961q134 298 203 501h188l8 -22q-40 -91 -111 -218.5t-159 -260.5h-129z" /> +<glyph unicode="&#x201a;" horiz-adv-x="492" d="M-100 -264q126 286 204 502h187l8 -23q-113 -235 -270 -479h-129z" /> +<glyph unicode="&#x201c;" horiz-adv-x="719" d="M123 983q98 211 270 479h127q-147 -345 -203 -501h-188zM492 983q80 181 272 479h127q-162 -379 -203 -501h-188z" /> +<glyph unicode="&#x201d;" horiz-adv-x="719" d="M125 961q134 298 203 501h188l8 -22q-40 -91 -111 -218.5t-159 -260.5h-129zM494 961q57 126 115.5 272.5t86.5 228.5h189l10 -22q-94 -206 -274 -479h-127z" /> +<glyph unicode="&#x201e;" horiz-adv-x="858" d="M-100 -264q126 286 204 502h187l8 -23q-113 -235 -270 -479h-129zM268 -264q140 316 203 502h188l9 -23q-95 -205 -271 -479h-129z" /> +<glyph unicode="&#x2022;" horiz-adv-x="774" d="M199 684q0 145 73.5 231t198.5 86q92 0 139 -49t47 -141q0 -141 -74 -230t-202 -89q-89 0 -135.5 49.5t-46.5 142.5z" /> +<glyph unicode="&#x2026;" horiz-adv-x="1563" d="M563 74q0 77 40.5 122.5t111.5 45.5q43 0 69.5 -26t26.5 -79q0 -71 -40 -118.5t-108 -47.5q-46 0 -73 26t-27 77zM1085 74q0 77 40.5 122.5t111.5 45.5q43 0 69.5 -26t26.5 -79q0 -71 -40 -118.5t-108 -47.5q-46 0 -73 26t-27 77zM43 74q0 77 40.5 122.5t111.5 45.5 q43 0 69.5 -26t26.5 -79q0 -71 -40 -118.5t-108 -47.5q-46 0 -73 26t-27 77z" /> +<glyph unicode="&#x202f;" horiz-adv-x="381" /> +<glyph unicode="&#x2039;" horiz-adv-x="580" d="M88 549v29l391 380l78 -81l-297 -334l172 -381l-113 -49z" /> +<glyph unicode="&#x203a;" horiz-adv-x="580" d="M23 197l296 333l-172 381l113 50l232 -437v-28l-392 -381z" /> +<glyph unicode="&#x2044;" horiz-adv-x="268" d="M-487 0l1085 1462h154l-1086 -1462h-153z" /> +<glyph unicode="&#x205f;" horiz-adv-x="476" /> +<glyph unicode="&#x2074;" horiz-adv-x="717" d="M92 788l23 101l481 579h133l-121 -563h127l-22 -117h-129l-43 -202h-127l43 202h-365zM256 905h225q69 322 90 395q-20 -36 -110 -149z" /> +<glyph unicode="&#x20ac;" d="M63 504l27 131h154q8 80 30 164h-151l27 133h159q97 267 259.5 408t369.5 141q89 0 160 -21.5t141 -70.5l-80 -138q-113 78 -231 78q-140 0 -254 -99t-189 -298h426l-26 -133h-441q-21 -65 -32 -164h381l-29 -131h-361q0 -373 297 -373q123 0 256 55v-147 q-127 -59 -278 -59q-212 0 -328.5 133.5t-116.5 378.5v12h-170z" /> +<glyph unicode="&#x2122;" horiz-adv-x="1534" d="M121 1358v104h516v-104h-199v-617h-121v617h-196zM705 741v721h180l182 -557l193 557h170v-721h-121v430q0 73 4 121h-6l-197 -551h-96l-189 551h-6q4 -52 4 -121v-430h-118z" /> +<glyph unicode="&#xe000;" horiz-adv-x="1095" d="M0 1095h1095v-1095h-1095v1095z" /> +<glyph unicode="&#xfb01;" horiz-adv-x="1165" d="M-229 -330q64 -22 112 -22q76 0 117 62t66 177l227 1082h-193l13 67l206 66l23 100q46 200 127.5 282.5t241.5 82.5q40 0 98 -11.5t90 -25.5l-43 -129q-76 29 -137 29q-87 0 -133.5 -48.5t-75.5 -177.5l-25 -108h238l-25 -127h-237l-232 -1098q-39 -189 -120 -276 t-213 -87q-69 0 -125 21v141zM702 0l234 1096h168l-234 -1096h-168zM983 1376q0 56 32 91.5t83 35.5q88 0 88 -90q0 -55 -33.5 -93t-77.5 -38q-40 0 -66 24.5t-26 69.5z" /> +<glyph unicode="&#xfb02;" horiz-adv-x="1165" d="M-229 -330q64 -22 112 -22q76 0 117 62t66 177l227 1082h-193l13 67l206 66l23 100q46 200 127.5 282.5t241.5 82.5q40 0 98 -11.5t90 -25.5l-43 -129q-76 29 -137 29q-87 0 -133.5 -48.5t-75.5 -177.5l-25 -108h238l-25 -127h-237l-232 -1098q-39 -189 -120 -276 t-213 -87q-69 0 -125 21v141zM700 0l332 1556h168l-332 -1556h-168z" /> +<glyph unicode="&#xfb03;" horiz-adv-x="1815" d="M-229 -330q64 -22 112 -22q70 0 114 58t69 181l227 1082h-193l13 67l206 66l23 100q46 200 127.5 282.5t241.5 82.5q40 0 98 -11.5t90 -25.5l-43 -129q-76 29 -137 29q-87 0 -133.5 -48.5t-75.5 -177.5l-25 -108h482l24 108q45 197 126 280t243 83q41 0 97.5 -11 t92.5 -26l-45 -129q-76 29 -137 29q-89 0 -135 -51t-74 -175l-24 -108h239l-26 -127h-238l-231 -1098q-43 -195 -123.5 -279t-210.5 -84q-71 0 -125 21v141q61 -22 115 -22q68 0 111 57.5t69 181.5l227 1082h-481l-232 -1098q-39 -189 -120 -276t-213 -87q-69 0 -125 21v141 zM1354 0l233 1096h168l-233 -1096h-168zM1634 1376q0 54 32 90.5t83 36.5q88 0 88 -90q0 -55 -33.5 -93t-77.5 -38q-38 0 -65 24.5t-27 69.5z" /> +<glyph unicode="&#xfb04;" horiz-adv-x="1815" d="M-229 -330q64 -22 112 -22q70 0 114 58t69 181l227 1082h-193l13 67l206 66l23 100q46 200 127.5 282.5t241.5 82.5q40 0 98 -11.5t90 -25.5l-43 -129q-76 29 -137 29q-87 0 -133.5 -48.5t-75.5 -177.5l-25 -108h482l24 108q45 197 126 280t243 83q41 0 97.5 -11 t92.5 -26l-45 -129q-76 29 -137 29q-89 0 -135 -51t-74 -175l-24 -108h239l-26 -127h-238l-231 -1098q-43 -195 -123.5 -279t-210.5 -84q-71 0 -125 21v141q61 -22 115 -22q68 0 111 57.5t69 181.5l227 1082h-481l-232 -1098q-39 -189 -120 -276t-213 -87q-69 0 -125 21v141 zM1352 0l331 1556h168l-331 -1556h-168z" /> +</font> +</defs></svg> +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Italic-webfont.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.svg b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.svg @@ -0,0 +1,252 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata> +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom +</metadata> +<defs> +<font id="OpenSansLight" horiz-adv-x="1169" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="&#x09;" horiz-adv-x="532" /> +<glyph unicode="&#xa0;" horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="492" d="M164 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98zM186 1462h119l-29 -1085h-61z" /> +<glyph unicode="&#x22;" horiz-adv-x="723" d="M133 1462h127l-33 -528h-61zM463 1462h127l-33 -528h-61z" /> +<glyph unicode="#" horiz-adv-x="1323" d="M55 451v79h299l76 398h-297v80h311l86 454h91l-89 -454h365l88 454h86l-88 -454h285v-80h-301l-76 -398h303v-79h-320l-86 -451h-90l88 451h-360l-86 -451h-88l86 451h-283zM440 530h363l78 398h-363z" /> +<glyph unicode="$" d="M164 186v103q75 -36 179.5 -61t193.5 -25v508q-145 44 -215 88t-102 104t-32 146q0 124 94.5 208.5t254.5 104.5v192h81v-190q197 -9 351 -72l-33 -90q-141 62 -318 72v-486q213 -66 293 -144t80 -204q0 -133 -99 -217t-274 -106v-236h-81v232q-92 2 -200.5 22.5 t-172.5 50.5zM297 1049q0 -86 57 -141t183 -93v453q-119 -16 -179.5 -76t-60.5 -143zM618 209q122 13 192.5 75t70.5 160q0 85 -63 140.5t-200 95.5v-471z" /> +<glyph unicode="%" horiz-adv-x="1653" d="M113 1026q0 223 72 340t212 117q139 0 215 -120.5t76 -336.5q0 -226 -75 -343.5t-216 -117.5q-133 0 -208.5 120.5t-75.5 340.5zM211 1026q0 -186 45 -279.5t141 -93.5q193 0 193 373q0 184 -49.5 276.5t-143.5 92.5q-96 0 -141 -92.5t-45 -276.5zM373 0l811 1462h96 l-811 -1462h-96zM965 438q0 225 73.5 341t212.5 116q137 0 213 -120t76 -337q0 -226 -74 -343.5t-215 -117.5q-136 0 -211 121.5t-75 339.5zM1063 438q0 -185 45 -277.5t141 -92.5q193 0 193 370q0 369 -193 369q-96 0 -141 -91.5t-45 -277.5z" /> +<glyph unicode="&#x26;" horiz-adv-x="1460" d="M123 371q0 138 73.5 235t274.5 205l-75 82q-66 71 -98 139t-32 142q0 143 95.5 227t256.5 84q155 0 245.5 -81t90.5 -224q0 -105 -70 -192.5t-253 -194.5l452 -457q61 72 104 157t75 201h96q-63 -246 -209 -426l266 -268h-135l-193 197q-92 -90 -164 -131.5t-157.5 -63.5 t-194.5 -22q-209 0 -328.5 103t-119.5 288zM227 375q0 -143 93 -224t258 -81q128 0 234.5 43.5t209.5 146.5l-483 485q-136 -72 -196.5 -122.5t-88 -109.5t-27.5 -138zM373 1176q0 -79 40 -146t152 -174q159 85 221 159t62 169q0 94 -62 152.5t-168 58.5q-114 0 -179.5 -58 t-65.5 -161z" /> +<glyph unicode="'" horiz-adv-x="393" d="M133 1462h127l-33 -528h-61z" /> +<glyph unicode="(" horiz-adv-x="557" d="M82 561q0 265 77.5 496t223.5 405h113q-148 -182 -227 -412.5t-79 -486.5q0 -483 304 -887h-111q-147 170 -224 397t-77 488z" /> +<glyph unicode=")" horiz-adv-x="557" d="M61 1462h113q147 -175 224 -406.5t77 -494.5t-77.5 -490t-223.5 -395h-111q304 404 304 887q0 257 -79 487.5t-227 411.5z" /> +<glyph unicode="*" horiz-adv-x="1128" d="M104 1124l19 131l401 -104l-39 405h146l-37 -405l405 104l21 -131l-395 -39l247 -340l-124 -71l-191 379l-180 -379l-125 71l242 340z" /> +<glyph unicode="+" d="M111 682v82h432v434h82v-434h434v-82h-434v-432h-82v432h-432z" /> +<glyph unicode="," horiz-adv-x="440" d="M68 -264q77 275 110 502h117l12 -21q-75 -265 -174 -481h-65z" /> +<glyph unicode="-" horiz-adv-x="659" d="M92 512v82h475v-82h-475z" /> +<glyph unicode="." horiz-adv-x="487" d="M162 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98z" /> +<glyph unicode="/" horiz-adv-x="698" d="M25 0l544 1462h105l-545 -1462h-104z" /> +<glyph unicode="0" d="M115 735q0 382 115.5 566t351.5 184q231 0 352 -190.5t121 -559.5q0 -385 -117.5 -570t-355.5 -185q-229 0 -348 190.5t-119 564.5zM223 735q0 -340 89 -502.5t270 -162.5q189 0 275.5 168t86.5 497q0 324 -86.5 492t-275.5 168t-274 -168t-85 -492z" /> +<glyph unicode="1" d="M199 1165l397 297h86v-1462h-98v1065q0 145 12 301q-15 -15 -31 -29t-309 -243z" /> +<glyph unicode="2" d="M113 0v88l389 406q164 170 230 260t97 172t31 172q0 131 -86 213t-223 82q-183 0 -350 -133l-54 69q183 154 406 154q191 0 300.5 -102t109.5 -281q0 -145 -73.5 -280.5t-268.5 -334.5l-375 -385v-4h782v-96h-915z" /> +<glyph unicode="3" d="M94 63v99q84 -44 188.5 -69t196.5 -25q221 0 332 89.5t111 252.5q0 145 -113.5 223t-333.5 78h-158v96h160q182 0 288.5 86.5t106.5 234.5q0 122 -86.5 195.5t-226.5 73.5q-109 0 -199 -30.5t-202 -104.5l-49 67q85 71 205 112.5t243 41.5q202 0 312 -95.5t110 -269.5 q0 -136 -85.5 -229t-229.5 -119v-6q176 -22 268 -112t92 -242q0 -205 -139.5 -317.5t-401.5 -112.5q-223 0 -389 83z" /> +<glyph unicode="4" d="M43 373v67l725 1030h121v-1011h252v-86h-252v-373h-94v373h-752zM162 459h633v418q0 302 14 507h-8q-20 -37 -123 -188z" /> +<glyph unicode="5" d="M143 63v103q108 -55 192 -76.5t179 -21.5q192 0 308 101.5t116 274.5q0 163 -113 256t-307 93q-130 0 -272 -39l-60 39l58 669h704v-96h-610l-45 -516q156 29 244 29q234 0 368.5 -113t134.5 -311q0 -225 -140 -350t-386 -125q-109 0 -207 21.5t-164 61.5z" /> +<glyph unicode="6" d="M131 623q0 285 77.5 479.5t220 288.5t343.5 94q94 0 172 -23v-88q-73 27 -176 27q-247 0 -384.5 -178t-154.5 -518h13q76 98 174 148t207 50q205 0 320.5 -117t115.5 -323q0 -224 -121.5 -353.5t-327.5 -129.5q-222 0 -350.5 169.5t-128.5 473.5zM240 504 q0 -111 49.5 -213.5t134 -162.5t186.5 -60q164 0 255 103t91 294q0 168 -90 262t-245 94q-102 0 -189.5 -45t-139.5 -119.5t-52 -152.5z" /> +<glyph unicode="7" d="M109 1366v96h946v-73l-604 -1389h-117l602 1366h-827z" /> +<glyph unicode="8" d="M121 375q0 131 83 230t257 169q-161 76 -227 160.5t-66 202.5q0 105 53 184.5t148.5 122.5t212.5 43q186 0 299.5 -95t113.5 -257q0 -112 -70.5 -198t-228.5 -159q192 -79 270 -173t78 -228q0 -181 -126.5 -289t-339.5 -108q-221 0 -339 101t-118 294zM223 360 q0 -138 93.5 -214t261.5 -76q164 0 264 80.5t100 218.5q0 124 -78.5 201.5t-302.5 162.5q-184 -71 -261 -157t-77 -216zM268 1137q0 -70 31.5 -123.5t91 -97t199.5 -101.5q163 63 234 139t71 183q0 120 -84.5 190t-230.5 70q-141 0 -226.5 -69.5t-85.5 -190.5z" /> +<glyph unicode="9" d="M111 993q0 220 124.5 356t323.5 136q144 0 252 -75.5t166.5 -221.5t58.5 -346q0 -288 -75.5 -482t-220 -287t-349.5 -93q-104 0 -192 26v86q43 -14 103.5 -21.5t92.5 -7.5q247 0 387 178.5t156 520.5h-12q-73 -96 -174 -147.5t-211 -51.5q-203 0 -316.5 112t-113.5 318z M213 999q0 -174 87 -264t249 -90q101 0 188.5 45t139 119.5t51.5 151.5q0 117 -46.5 219t-130 159.5t-192.5 57.5q-158 0 -252 -106.5t-94 -291.5z" /> +<glyph unicode=":" horiz-adv-x="487" d="M162 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98zM162 971q0 98 80 98q82 0 82 -98q0 -53 -23.5 -76t-58.5 -23q-34 0 -57 23t-23 76z" /> +<glyph unicode=";" horiz-adv-x="487" d="M76 -264q29 97 62 245.5t48 256.5h117l12 -21q-75 -265 -174 -481h-65zM162 971q0 98 80 98q82 0 82 -98q0 -53 -23.5 -76t-58.5 -23q-34 0 -57 23t-23 76z" /> +<glyph unicode="&#x3c;" d="M111 682v61l948 474v-95l-823 -405l823 -355v-96z" /> +<glyph unicode="=" d="M111 477v82h948v-82h-948zM111 885v82h948v-82h-948z" /> +<glyph unicode="&#x3e;" d="M111 266v96l823 355l-823 405v95l948 -474v-61z" /> +<glyph unicode="?" horiz-adv-x="862" d="M57 1403q110 48 184.5 64t153.5 16q183 0 288 -98.5t105 -270.5q0 -68 -18 -119t-50.5 -94.5t-78.5 -84t-102 -87.5q-64 -54 -98.5 -98.5t-50 -93.5t-15.5 -146v-14h-82v37q0 123 37.5 201t138.5 167l91 79q72 61 103 121t31 138q0 127 -83.5 202t-219.5 75 q-79 0 -148 -17.5t-149 -56.5zM260 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98z" /> +<glyph unicode="@" horiz-adv-x="1815" d="M113 561q0 256 108.5 460.5t307 317.5t448.5 113q215 0 380.5 -89t255 -254.5t89.5 -383.5q0 -228 -90.5 -366t-245.5 -138q-89 0 -144.5 54t-64.5 147h-4q-43 -100 -124 -150.5t-189 -50.5q-148 0 -229 96.5t-81 270.5q0 202 120.5 330.5t314.5 128.5q138 0 286 -41 l-22 -464v-30q0 -104 35 -156.5t116 -52.5q103 0 168.5 116.5t65.5 303.5q0 194 -79 340t-225.5 224.5t-334.5 78.5q-230 0 -405.5 -99.5t-270 -281.5t-94.5 -418q0 -322 167 -497.5t474 -175.5q93 0 188.5 18t231.5 70v-99q-203 -80 -414 -80q-349 0 -544 200.5t-195 557.5 zM633 590q0 -143 55 -215t174 -72q255 0 273 346l16 291q-79 27 -193 27q-149 0 -237 -102.5t-88 -274.5z" /> +<glyph unicode="A" horiz-adv-x="1229" d="M0 0l588 1468h65l576 -1468h-115l-203 516h-594l-204 -516h-113zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174z" /> +<glyph unicode="B" horiz-adv-x="1284" d="M207 0v1462h401q271 0 398 -92t127 -278q0 -127 -77.5 -211.5t-226.5 -108.5v-6q175 -26 257.5 -110.5t82.5 -235.5q0 -202 -134 -311t-380 -109h-448zM309 90h344q406 0 406 330q0 301 -428 301h-322v-631zM309 811h322q206 0 299.5 68.5t93.5 214.5t-105.5 212 t-314.5 66h-295v-561z" /> +<glyph unicode="C" horiz-adv-x="1272" d="M129 735q0 223 84.5 393t243 262.5t368.5 92.5q214 0 383 -80l-41 -92q-160 80 -336 80q-275 0 -433 -176t-158 -482q0 -313 149 -486t426 -173q184 0 338 47v-90q-145 -51 -362 -51q-308 0 -485 199t-177 556z" /> +<glyph unicode="D" horiz-adv-x="1446" d="M207 0v1462h395q350 0 532.5 -183t182.5 -534q0 -368 -193 -556.5t-567 -188.5h-350zM309 90h242q655 0 655 651q0 314 -159.5 472.5t-468.5 158.5h-269v-1282z" /> +<glyph unicode="E" horiz-adv-x="1130" d="M207 0v1462h799v-94h-697v-553h658v-94h-658v-627h697v-94h-799z" /> +<glyph unicode="F" horiz-adv-x="1028" d="M207 0v1462h801v-94h-699v-620h660v-95h-660v-653h-102z" /> +<glyph unicode="G" horiz-adv-x="1481" d="M129 729q0 223 91.5 395.5t262 266.5t391.5 94q239 0 429 -88l-41 -92q-190 88 -394 88q-289 0 -458.5 -178.5t-169.5 -481.5q0 -330 161 -496.5t473 -166.5q202 0 343 57v514h-435v96h539v-667q-212 -90 -477 -90q-346 0 -530.5 195.5t-184.5 553.5z" /> +<glyph unicode="H" horiz-adv-x="1473" d="M207 0v1462h102v-649h854v649h103v-1462h-103v719h-854v-719h-102z" /> +<glyph unicode="I" horiz-adv-x="516" d="M207 0v1462h102v-1462h-102z" /> +<glyph unicode="J" horiz-adv-x="506" d="M-184 -254q78 -20 149 -20q242 0 242 264v1472h102v-1462q0 -369 -342 -369q-92 0 -151 27v88z" /> +<glyph unicode="K" horiz-adv-x="1190" d="M207 0v1462h102v-760l162 162l573 598h130l-599 -618l615 -844h-125l-561 772l-195 -172v-600h-102z" /> +<glyph unicode="L" horiz-adv-x="1051" d="M207 0v1462h102v-1366h697v-96h-799z" /> +<glyph unicode="M" horiz-adv-x="1767" d="M207 0v1462h158l518 -1286h6l518 1286h154v-1462h-103v1108q0 116 12 240h-8l-547 -1348h-65l-545 1350h-8q8 -124 8 -254v-1096h-98z" /> +<glyph unicode="N" horiz-adv-x="1477" d="M207 0v1462h102l865 -1296h6q-9 180 -9 342v954h99v-1462h-103l-866 1298h-8q12 -232 12 -350v-948h-98z" /> +<glyph unicode="O" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170 t-141.5 -483z" /> +<glyph unicode="P" horiz-adv-x="1198" d="M207 0v1462h358q522 0 522 -420q0 -212 -144 -325t-408 -113h-226v-604h-102zM309 692h201q247 0 357 81.5t110 264.5q0 169 -104 250.5t-322 81.5h-242v-678z" /> +<glyph unicode="Q" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5q0 -294 -126 -486.5t-349 -246.5l333 -348h-166l-282 330l-33 -2h-31q-305 0 -479 202.5t-174 552.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5 t-401.5 168.5q-261 0 -402.5 -170t-141.5 -483z" /> +<glyph unicode="R" horiz-adv-x="1217" d="M207 0v1462h348q272 0 402 -100.5t130 -302.5q0 -147 -77.5 -248t-235.5 -145l397 -666h-122l-377 637h-363v-637h-102zM309 725h279q185 0 287 82.5t102 243.5q0 167 -100 243t-326 76h-242v-645z" /> +<glyph unicode="S" horiz-adv-x="1116" d="M111 39v102q158 -67 403 -67q180 0 285.5 82.5t105.5 216.5q0 83 -35 137.5t-114 99.5t-232 97q-224 77 -309.5 166.5t-85.5 238.5q0 164 128.5 267.5t330.5 103.5q206 0 387 -78l-37 -88q-182 76 -348 76q-162 0 -258 -75t-96 -204q0 -81 29.5 -133t96.5 -93.5 t230 -99.5q171 -59 257 -114.5t125.5 -126t39.5 -170.5q0 -183 -134.5 -290t-357.5 -107q-268 0 -411 59z" /> +<glyph unicode="T" horiz-adv-x="1073" d="M10 1366v96h1053v-96h-475v-1366h-103v1366h-475z" /> +<glyph unicode="U" horiz-adv-x="1473" d="M190 520v942h103v-946q0 -211 117 -328.5t331 -117.5q209 0 324 115.5t115 320.5v956h102v-946q0 -252 -146 -394t-407 -142q-254 0 -396.5 142.5t-142.5 397.5z" /> +<glyph unicode="V" horiz-adv-x="1182" d="M0 1462h109l368 -995q84 -225 113 -338q20 75 79 233l402 1100h111l-547 -1462h-90z" /> +<glyph unicode="W" horiz-adv-x="1827" d="M51 1462h107l256 -942q15 -57 28 -105.5t23.5 -91t19 -82t15.5 -79.5q24 136 102 413l250 887h113l293 -1018q51 -176 73 -284q13 72 33.5 153t308.5 1149h103l-404 -1462h-84l-321 1128q-40 139 -60 228q-16 -87 -45.5 -200t-322.5 -1156h-86z" /> +<glyph unicode="X" horiz-adv-x="1102" d="M0 0l492 762l-447 700h115l395 -626l401 626h109l-453 -698l490 -764h-117l-432 682l-440 -682h-113z" /> +<glyph unicode="Y" horiz-adv-x="1081" d="M0 1462h117l426 -800l428 800h110l-487 -897v-565h-105v557z" /> +<glyph unicode="Z" horiz-adv-x="1180" d="M82 0v76l856 1290h-817v96h954v-76l-858 -1290h881v-96h-1016z" /> +<glyph unicode="[" horiz-adv-x="653" d="M174 -324v1786h428v-94h-330v-1597h330v-95h-428z" /> +<glyph unicode="\" horiz-adv-x="698" d="M25 1462h102l547 -1462h-103z" /> +<glyph unicode="]" horiz-adv-x="653" d="M51 -229h330v1597h-330v94h428v-1786h-428v95z" /> +<glyph unicode="^" d="M88 561l465 912h68l460 -912h-100l-395 791l-398 -791h-100z" /> +<glyph unicode="_" horiz-adv-x="842" d="M-4 -184h850v-82h-850v82z" /> +<glyph unicode="`" horiz-adv-x="1182" d="M393 1552v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="a" horiz-adv-x="1085" d="M98 289q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227zM203 285q0 -102 62.5 -158.5t176.5 -56.5 q174 0 274.5 99.5t100.5 276.5v107l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5z" /> +<glyph unicode="b" horiz-adv-x="1219" d="M182 0v1556h99v-391q0 -88 -4 -162l-3 -85h7q62 98 149.5 144t210.5 46q228 0 343.5 -143.5t115.5 -419.5q0 -271 -121.5 -418t-341.5 -147q-116 0 -209 48t-147 136h-9l-28 -164h-62zM281 528q0 -246 86.5 -353t269.5 -107q178 0 268 124.5t90 354.5q0 471 -356 471 q-192 0 -275 -110t-83 -363v-17z" /> +<glyph unicode="c" horiz-adv-x="973" d="M119 537q0 270 137 420.5t375 150.5q141 0 270 -49l-27 -88q-141 47 -245 47q-200 0 -303 -123.5t-103 -355.5q0 -220 103 -344.5t288 -124.5q148 0 275 53v-92q-104 -51 -273 -51q-233 0 -365 147t-132 410z" /> +<glyph unicode="d" horiz-adv-x="1219" d="M119 528q0 282 118 431t343 149q118 0 204 -43t154 -147h6q-6 126 -6 247v391h98v-1556h-65l-25 166h-8q-124 -186 -356 -186q-225 0 -344 140t-119 408zM223 530q0 -462 359 -462q184 0 270 107t86 353v17q0 252 -84.5 362.5t-273.5 110.5q-178 0 -267.5 -125 t-89.5 -363z" /> +<glyph unicode="e" horiz-adv-x="1124" d="M119 535q0 260 128 416.5t345 156.5q192 0 303 -134t111 -364v-80h-783q2 -224 104.5 -342t293.5 -118q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5q-237 0 -369.5 146t-132.5 409zM229 618h672q0 189 -82 295.5t-227 106.5q-157 0 -252 -103.5 t-111 -298.5z" /> +<glyph unicode="f" horiz-adv-x="614" d="M29 1001v58l202 37v84q0 200 73.5 293.5t240.5 93.5q90 0 180 -27l-23 -86q-80 25 -159 25q-116 0 -164.5 -68.5t-48.5 -222.5v-101h256v-86h-256v-1001h-99v1001h-202z" /> +<glyph unicode="g" horiz-adv-x="1071" d="M45 -193q0 112 69.5 186t188.5 101q-49 21 -78.5 59.5t-29.5 88.5q0 109 139 192q-95 39 -148 122.5t-53 191.5q0 163 103.5 261.5t279.5 98.5q107 0 166 -21h348v-69l-225 -14q90 -112 90 -246q0 -157 -104.5 -254.5t-280.5 -97.5q-74 0 -104 6q-59 -31 -90 -73t-31 -89 q0 -52 39.5 -76t132.5 -24h190q177 0 271 -71.5t94 -211.5q0 -172 -139.5 -265.5t-397.5 -93.5q-205 0 -317.5 79t-112.5 220zM150 -184q0 -224 333 -224q428 0 428 273q0 98 -67 142t-217 44h-178q-299 0 -299 -235zM233 748q0 -126 76.5 -195.5t204.5 -69.5 q136 0 208.5 69t72.5 200q0 139 -74.5 208.5t-208.5 69.5q-130 0 -204.5 -74.5t-74.5 -207.5z" /> +<glyph unicode="h" horiz-adv-x="1208" d="M182 0v1556h99v-495l-5 -139h7q61 98 154 142t231 44q370 0 370 -397v-711h-98v705q0 164 -69 238.5t-214 74.5q-195 0 -285.5 -98.5t-90.5 -319.5v-600h-99z" /> +<glyph unicode="i" horiz-adv-x="463" d="M168 1389q0 96 63 96q31 0 48.5 -25t17.5 -71q0 -45 -17.5 -71t-48.5 -26q-63 0 -63 97zM182 0v1087h99v-1087h-99z" /> +<glyph unicode="j" horiz-adv-x="463" d="M-98 -381q69 -20 129 -20q151 0 151 176v1312h99v-1298q0 -135 -63.5 -208t-180.5 -73q-80 0 -135 25v86zM168 1389q0 96 63 96q31 0 48.5 -25t17.5 -71q0 -45 -17.5 -71t-48.5 -26q-63 0 -63 97z" /> +<glyph unicode="k" horiz-adv-x="991" d="M182 0v1556h99v-780l-7 -299h5l555 610h120l-428 -464l465 -623h-119l-413 549l-178 -162v-387h-99z" /> +<glyph unicode="l" horiz-adv-x="463" d="M182 0v1556h99v-1556h-99z" /> +<glyph unicode="m" horiz-adv-x="1808" d="M182 0v1087h82l21 -149h6q45 81 128 125.5t183 44.5q257 0 330 -193h4q53 93 142.5 143t203.5 50q178 0 267 -95t89 -302v-711h-98v713q0 159 -62 232t-190 73q-167 0 -247 -92t-80 -289v-637h-101v743q0 275 -252 275q-171 0 -249 -99.5t-78 -318.5v-600h-99z" /> +<glyph unicode="n" horiz-adv-x="1208" d="M182 0v1087h84l19 -149h6q106 170 377 170q370 0 370 -397v-711h-98v705q0 164 -69 238.5t-214 74.5q-195 0 -285.5 -98.5t-90.5 -319.5v-600h-99z" /> +<glyph unicode="o" horiz-adv-x="1200" d="M119 545q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z " /> +<glyph unicode="p" horiz-adv-x="1219" d="M182 -492v1579h84l19 -155h6q112 176 358 176q220 0 335.5 -144.5t115.5 -420.5q0 -268 -121.5 -415.5t-331.5 -147.5q-251 0 -366 188h-7l3 -84q4 -74 4 -162v-414h-99zM281 541q0 -255 85.5 -364t278.5 -109q167 0 258.5 124t91.5 347q0 479 -346 479 q-190 0 -279 -104.5t-89 -340.5v-32z" /> +<glyph unicode="q" horiz-adv-x="1219" d="M119 532q0 275 118 425.5t338 150.5q236 0 353 -174h6l18 153h84v-1579h-98v414q0 122 6 248h-6q-118 -190 -369 -190q-214 0 -332 142t-118 410zM223 530q0 -229 89.5 -345.5t258.5 -116.5q198 0 282.5 109t84.5 366v12q0 245 -85 354t-271 109q-176 0 -267.5 -124 t-91.5 -364z" /> +<glyph unicode="r" horiz-adv-x="797" d="M182 0v1087h84l10 -196h7q67 120 143 168.5t184 48.5q69 0 148 -14l-19 -95q-68 17 -141 17q-139 0 -228 -118t-89 -298v-600h-99z" /> +<glyph unicode="s" horiz-adv-x="954" d="M84 47v107q164 -82 346 -82q161 0 244.5 53.5t83.5 142.5q0 82 -66.5 138t-218.5 110q-163 59 -229 101.5t-99.5 96t-33.5 130.5q0 122 102.5 193t286.5 71q176 0 334 -66l-37 -90q-160 66 -297 66q-133 0 -211 -44t-78 -122q0 -85 60.5 -136t236.5 -114 q147 -53 214 -95.5t100.5 -96.5t33.5 -127q0 -146 -111 -224.5t-315 -78.5q-218 0 -346 67z" /> +<glyph unicode="t" horiz-adv-x="686" d="M25 1001v58l161 45l50 246h51v-263h319v-86h-319v-688q0 -125 44 -185t138 -60t164 16v-80q-72 -24 -166 -24q-144 0 -212.5 77t-68.5 242v702h-161z" /> +<glyph unicode="u" horiz-adv-x="1208" d="M170 377v710h98v-704q0 -164 69 -238.5t214 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-106 -170 -377 -170q-371 0 -371 397z" /> +<glyph unicode="v" horiz-adv-x="940" d="M0 1087h102l281 -739q56 -142 84 -248h6q41 136 84 250l281 737h102l-420 -1087h-100z" /> +<glyph unicode="w" horiz-adv-x="1481" d="M31 1087h106l174 -630q61 -234 80 -344h6q59 234 86 311l224 663h90l213 -661q72 -235 88 -311h6q8 65 80 348l166 624h100l-295 -1087h-104l-238 727q-23 74 -59 217h-6l-21 -74l-45 -145l-242 -725h-98z" /> +<glyph unicode="x" horiz-adv-x="1020" d="M55 0l394 559l-379 528h114l324 -458l321 458h109l-373 -528l400 -559h-115l-342 485l-344 -485h-109z" /> +<glyph unicode="y" horiz-adv-x="940" d="M0 1087h102l230 -610q105 -281 133 -379h6q42 129 137 385l230 604h102l-487 -1263q-59 -154 -99 -208t-93.5 -81t-129.5 -27q-57 0 -127 21v86q58 -16 125 -16q51 0 90 24t70.5 74.5t73 160t53.5 142.5z" /> +<glyph unicode="z" horiz-adv-x="944" d="M82 0v63l645 936h-598v88h727v-63l-649 -936h651v-88h-776z" /> +<glyph unicode="{" horiz-adv-x="723" d="M61 528v80q122 2 176 51t54 148v350q0 299 360 305v-90q-138 -5 -200 -58t-62 -157v-305q0 -130 -44 -194t-142 -85v-8q97 -20 141.5 -83.5t44.5 -186.5v-322q0 -102 59.5 -152.5t202.5 -53.5v-91q-195 0 -277.5 75t-82.5 231v337q0 205 -230 209z" /> +<glyph unicode="|" horiz-adv-x="1108" d="M508 -506v2067h92v-2067h-92z" /> +<glyph unicode="}" horiz-adv-x="723" d="M72 -233q141 2 201.5 52.5t60.5 153.5v322q0 123 44.5 186.5t141.5 83.5v8q-97 20 -141.5 84t-44.5 195v305q0 103 -61.5 156.5t-200.5 58.5v90q174 0 267 -77.5t93 -227.5v-350q0 -100 54.5 -148.5t175.5 -50.5v-80q-230 -4 -230 -209v-337q0 -155 -82.5 -230.5 t-277.5 -75.5v91z" /> +<glyph unicode="~" d="M111 625v94q108 110 233 110q61 0 115 -13.5t155 -57.5q126 -58 220 -58q56 0 109.5 30.5t115.5 94.5v-96q-48 -49 -104.5 -81t-129.5 -32q-116 0 -270 72q-124 57 -221 57q-49 0 -108 -30.5t-115 -89.5z" /> +<glyph unicode="&#xa1;" horiz-adv-x="492" d="M166 1010q0 98 80 98q82 0 82 -98q0 -53 -23.5 -76t-58.5 -23q-34 0 -57 23t-23 76zM186 -375l29 1086h61l29 -1086h-119z" /> +<glyph unicode="&#xa2;" d="M211 745q0 232 102.5 381.5t288.5 182.5v174h82v-166h14q131 0 275 -55l-31 -84q-134 51 -237 51q-187 0 -288.5 -122.5t-101.5 -358.5q0 -225 100.5 -349.5t280.5 -124.5q131 0 267 58v-92q-110 -56 -267 -56h-12v-204h-82v210q-186 30 -288.5 175t-102.5 380z" /> +<glyph unicode="&#xa3;" d="M78 0v84q110 21 171.5 110t61.5 224v258h-211v82h211v297q0 204 98 315t281 111q175 0 330 -68l-35 -86q-157 66 -295 66q-141 0 -209.5 -81t-68.5 -253v-301h411v-82h-411v-256q0 -116 -35 -196t-113 -128h809v-96h-995z" /> +<glyph unicode="&#xa4;" d="M127 326l139 141q-90 106 -90 256q0 147 90 258l-139 141l59 60l138 -142q103 93 260 93q155 0 260 -93l137 142l59 -60l-139 -141q90 -111 90 -258q0 -151 -90 -256l139 -141l-59 -60l-137 142q-110 -93 -260 -93q-153 0 -260 93l-138 -142zM260 723q0 -136 94.5 -232 t229.5 -96q134 0 228.5 95.5t94.5 232.5q0 136 -95 233t-228 97q-134 0 -229 -97t-95 -233z" /> +<glyph unicode="&#xa5;" d="M43 1462h117l426 -796l428 796h110l-432 -788h283v-82h-338v-205h338v-82h-338v-305h-105v305h-337v82h337v205h-337v82h278z" /> +<glyph unicode="&#xa6;" horiz-adv-x="1108" d="M508 258h92v-764h-92v764zM508 797v764h92v-764h-92z" /> +<glyph unicode="&#xa7;" horiz-adv-x="1057" d="M129 63v95q182 -78 332 -78q162 0 247 49.5t85 140.5q0 55 -25 87.5t-88.5 65.5t-190.5 79q-200 73 -272 141.5t-72 169.5q0 83 50.5 152.5t138.5 107.5q-86 47 -125 102t-39 136q0 117 101.5 183.5t275.5 66.5q175 0 336 -64l-35 -80q-91 34 -158.5 47t-144.5 13 q-134 0 -205.5 -44.5t-71.5 -119.5q0 -54 25.5 -88.5t85.5 -65.5t188 -74q192 -64 264 -132.5t72 -170.5q0 -173 -186 -274q86 -42 129 -96t43 -136q0 -135 -113 -207.5t-311 -72.5q-92 0 -171 15t-165 52zM246 825q0 -65 31.5 -104t105.5 -75t250 -99q82 41 126 98t44 121 q0 62 -32 102t-108.5 77t-236.5 87q-81 -23 -130.5 -79t-49.5 -128z" /> +<glyph unicode="&#xa8;" horiz-adv-x="1182" d="M336 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM717 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="&#xa9;" horiz-adv-x="1704" d="M100 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM193 731q0 -178 88.5 -329.5t240.5 -240.5t330 -89t329.5 88.5t240.5 240.5t89 330q0 174 -85.5 325 t-239 243t-334.5 92q-176 0 -328.5 -88.5t-241.5 -242.5t-89 -329zM489 725q0 208 111 332.5t297 124.5q119 0 227 -52l-37 -83q-98 45 -190 45q-142 0 -222.5 -94.5t-80.5 -264.5q0 -186 74.5 -275t220.5 -89q84 0 198 43v-88q-102 -45 -208 -45q-187 0 -288.5 115 t-101.5 331z" /> +<glyph unicode="&#xaa;" horiz-adv-x="686" d="M78 989q0 100 80 151.5t241 59.5l95 4v43q0 77 -38 114.5t-106 37.5q-87 0 -196 -49l-33 73q117 56 231 56q228 0 228 -215v-451h-68l-25 72q-84 -84 -202 -84q-95 0 -151 49t-56 139zM168 993q0 -54 35 -85t96 -31q90 0 142.5 50t52.5 142v64l-88 -5q-116 -6 -177 -36.5 t-61 -98.5z" /> +<glyph unicode="&#xab;" horiz-adv-x="885" d="M82 516v27l309 393l62 -43l-254 -363l254 -362l-62 -43zM442 516v27l310 393l61 -43l-254 -363l254 -362l-61 -43z" /> +<glyph unicode="&#xac;" d="M111 682v82h927v-494h-82v412h-845z" /> +<glyph unicode="&#xad;" horiz-adv-x="659" d="M92 512v82h475v-82h-475z" /> +<glyph unicode="&#xae;" horiz-adv-x="1704" d="M100 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM193 731q0 -178 88.5 -329.5t240.5 -240.5t330 -89t329.5 88.5t240.5 240.5t89 330q0 174 -85.5 325 t-239 243t-334.5 92q-176 0 -328.5 -88.5t-241.5 -242.5t-89 -329zM608 291v880h211q143 0 222 -62t79 -191q0 -79 -38.5 -139.5t-110.5 -94.5l237 -393h-121l-210 360h-168v-360h-101zM709 731h112q91 0 143 46.5t52 135.5q0 172 -197 172h-110v-354z" /> +<glyph unicode="&#xaf;" horiz-adv-x="1024" d="M-6 1556v82h1036v-82h-1036z" /> +<glyph unicode="&#xb0;" horiz-adv-x="877" d="M139 1184q0 132 86.5 215.5t212.5 83.5t212.5 -83.5t86.5 -215.5t-86.5 -215.5t-212.5 -83.5q-130 0 -214.5 83t-84.5 216zM229 1184q0 -91 61 -154t148 -63q86 0 147.5 62t61.5 155q0 92 -60 154.5t-149 62.5q-90 0 -149.5 -64t-59.5 -153z" /> +<glyph unicode="&#xb1;" d="M111 1v82h948v-82h-948zM111 682v82h432v434h82v-434h434v-82h-434v-432h-82v432h-432z" /> +<glyph unicode="&#xb2;" horiz-adv-x="688" d="M53 586v78l242 237q125 121 172 193t47 149q0 71 -46.5 112.5t-123.5 41.5q-108 0 -217 -82l-49 65q119 103 270 103q124 0 194 -63.5t70 -174.5q0 -47 -13 -89t-40 -85.5t-68.5 -90t-308.5 -306.5h447v-88h-576z" /> +<glyph unicode="&#xb3;" horiz-adv-x="688" d="M41 629v88q136 -62 266 -62q115 0 174.5 49t59.5 136q0 83 -59.5 122t-178.5 39h-131v84h135q105 0 158 43.5t53 120.5q0 67 -47 107.5t-127 40.5q-128 0 -246 -78l-47 70q130 94 293 94q127 0 199.5 -60t72.5 -163q0 -78 -44 -131.5t-117 -75.5q186 -45 186 -211 q0 -130 -88.5 -201.5t-247.5 -71.5q-144 0 -264 60z" /> +<glyph unicode="&#xb4;" horiz-adv-x="1182" d="M393 1241v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="&#xb5;" horiz-adv-x="1221" d="M182 -492v1579h99v-704q0 -164 69 -238.5t213 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-50 -77 -150 -123.5t-217 -46.5q-99 0 -167.5 27.5t-119.5 84.5q5 -92 5 -170v-414h-99z" /> +<glyph unicode="&#xb6;" horiz-adv-x="1341" d="M113 1042q0 260 109 387t341 127h543v-1816h-100v1722h-228v-1722h-100v819q-64 -18 -146 -18q-216 0 -317.5 125t-101.5 376z" /> +<glyph unicode="&#xb7;" horiz-adv-x="487" d="M162 721q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98z" /> +<glyph unicode="&#xb8;" horiz-adv-x="420" d="M43 -393q30 -10 92 -10q78 0 119 28t41 80q0 94 -193 121l93 174h96l-66 -117q168 -37 168 -174q0 -100 -67.5 -150.5t-188.5 -50.5q-68 0 -94 11v88z" /> +<glyph unicode="&#xb9;" horiz-adv-x="688" d="M76 1298l274 164h92v-876h-98v547q0 99 12 233q-26 -23 -233 -145z" /> +<glyph unicode="&#xba;" horiz-adv-x="739" d="M70 1141q0 162 78 250t223 88q142 0 220.5 -87t78.5 -251q0 -161 -80 -250.5t-223 -89.5t-220 86t-77 254zM160 1141q0 -264 209 -264t209 264q0 131 -50 194.5t-159 63.5t-159 -63.5t-50 -194.5z" /> +<glyph unicode="&#xbb;" horiz-adv-x="885" d="M72 168l254 362l-254 363l61 43l309 -391v-27l-309 -393zM432 168l254 362l-254 363l62 43l309 -391v-27l-309 -393z" /> +<glyph unicode="&#xbc;" horiz-adv-x="1516" d="M59 1298l274 164h92v-876h-98v547q0 99 12 233q-26 -23 -233 -145zM243 0l811 1462h94l-811 -1462h-94zM760 242v60l407 581h96v-563h129v-78h-129v-241h-90v241h-413zM864 320h309v221q0 132 8 232q-6 -12 -21.5 -35.5t-295.5 -417.5z" /> +<glyph unicode="&#xbd;" horiz-adv-x="1516" d="M11 1298l274 164h92v-876h-98v547q0 99 12 233q-26 -23 -233 -145zM168 0l811 1462h94l-811 -1462h-94zM827 1v78l242 237q125 121 172 193t47 149q0 71 -46.5 112.5t-123.5 41.5q-108 0 -217 -82l-49 65q119 103 270 103q124 0 194 -63.5t70 -174.5q0 -47 -13 -89 t-40 -85.5t-68.5 -90t-308.5 -306.5h447v-88h-576z" /> +<glyph unicode="&#xbe;" horiz-adv-x="1516" d="M41 629v88q136 -62 266 -62q115 0 174.5 49t59.5 136q0 83 -59.5 122t-178.5 39h-131v84h135q105 0 158 43.5t53 120.5q0 67 -47 107.5t-127 40.5q-128 0 -246 -78l-47 70q130 94 293 94q127 0 199.5 -60t72.5 -163q0 -78 -44 -131.5t-117 -75.5q186 -45 186 -211 q0 -130 -88.5 -201.5t-247.5 -71.5q-144 0 -264 60zM395 0l811 1462h94l-811 -1462h-94zM863 242v60l407 581h96v-563h129v-78h-129v-241h-90v241h-413zM967 320h309v221q0 132 8 232q-6 -12 -21.5 -35.5t-295.5 -417.5z" /> +<glyph unicode="&#xbf;" horiz-adv-x="862" d="M74 -27q0 70 20 124t58.5 102t171.5 159q64 53 98.5 98.5t49.5 94t15 145.5v15h82v-37q0 -125 -39.5 -204.5t-136.5 -164.5l-90 -79q-73 -61 -104 -120.5t-31 -138.5q0 -124 82 -200t221 -76q125 0 233 46l64 27l37 -79q-111 -48 -185.5 -64t-152.5 -16q-184 0 -288.5 99 t-104.5 269zM440 1010q0 98 80 98q82 0 82 -98q0 -53 -23.5 -76t-58.5 -23q-34 0 -57 23t-23 76z" /> +<glyph unicode="&#xc0;" horiz-adv-x="1229" d="M0 0l588 1468h65l576 -1468h-115l-203 516h-594l-204 -516h-113zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174zM337 1890v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="&#xc1;" horiz-adv-x="1229" d="M0 0l588 1468h65l576 -1468h-115l-203 516h-594l-204 -516h-113zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174zM504 1579v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="&#xc2;" horiz-adv-x="1229" d="M0 0l588 1468h65l576 -1468h-115l-203 516h-594l-204 -516h-113zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174zM328 1579v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="&#xc3;" horiz-adv-x="1229" d="M0 0l588 1468h65l576 -1468h-115l-203 516h-594l-204 -516h-113zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174zM287 1581q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61 q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73z" /> +<glyph unicode="&#xc4;" horiz-adv-x="1229" d="M0 0l588 1468h65l576 -1468h-115l-203 516h-594l-204 -516h-113zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174zM367 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM748 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="&#xc5;" horiz-adv-x="1229" d="M0 0l588 1468h65l576 -1468h-115l-203 516h-594l-204 -516h-113zM354 608h523l-199 527q-25 62 -60 172q-27 -96 -59 -174zM402 1610q0 94 60 152.5t157 58.5t157 -59t60 -152q0 -97 -60 -155t-157 -58t-157 58t-60 155zM482 1610q0 -66 37.5 -103.5t99.5 -37.5 t99.5 37.5t37.5 103.5q0 64 -39 101.5t-98 37.5q-62 0 -99.5 -38t-37.5 -101z" /> +<glyph unicode="&#xc6;" horiz-adv-x="1653" d="M-2 0l653 1462h877v-94h-615v-553h576v-94h-576v-627h615v-94h-717v516h-475l-227 -516h-111zM377 608h434v760h-100z" /> +<glyph unicode="&#xc7;" horiz-adv-x="1272" d="M129 735q0 223 84.5 393t243 262.5t368.5 92.5q214 0 383 -80l-41 -92q-160 80 -336 80q-275 0 -433 -176t-158 -482q0 -313 149 -486t426 -173q184 0 338 47v-90q-145 -51 -362 -51q-308 0 -485 199t-177 556zM561 -393q30 -10 92 -10q78 0 119 28t41 80q0 94 -193 121 l93 174h96l-66 -117q168 -37 168 -174q0 -100 -67.5 -150.5t-188.5 -50.5q-68 0 -94 11v88z" /> +<glyph unicode="&#xc8;" horiz-adv-x="1130" d="M207 0v1462h799v-94h-697v-553h658v-94h-658v-627h697v-94h-799zM314 1890v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="&#xc9;" horiz-adv-x="1130" d="M207 0v1462h799v-94h-697v-553h658v-94h-658v-627h697v-94h-799zM463 1579v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="&#xca;" horiz-adv-x="1130" d="M207 0v1462h799v-94h-697v-553h658v-94h-658v-627h697v-94h-799zM315 1579v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="&#xcb;" horiz-adv-x="1130" d="M207 0v1462h799v-94h-697v-553h658v-94h-658v-627h697v-94h-799zM354 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM735 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="&#xcc;" horiz-adv-x="516" d="M207 0v1462h102v-1462h-102zM-63 1890v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="&#xcd;" horiz-adv-x="516" d="M207 0v1462h102v-1462h-102zM191 1579v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="&#xce;" horiz-adv-x="516" d="M207 0v1462h102v-1462h-102zM-32 1579v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="&#xcf;" horiz-adv-x="516" d="M207 0v1462h102v-1462h-102zM5 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM386 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="&#xd0;" horiz-adv-x="1466" d="M47 678v94h160v690h395q350 0 532.5 -183t182.5 -534q0 -368 -193 -556.5t-567 -188.5h-350v678h-160zM309 90h242q655 0 655 651q0 314 -159.5 472.5t-468.5 158.5h-269v-600h406v-94h-406v-588z" /> +<glyph unicode="&#xd1;" horiz-adv-x="1477" d="M207 0v1462h102l865 -1296h6q-9 180 -9 342v954h99v-1462h-103l-866 1298h-8q12 -232 12 -350v-948h-98zM400 1581q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61q-36 0 -75 18.5t-101 71.5 q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73z" /> +<glyph unicode="&#xd2;" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170 t-141.5 -483zM502 1890v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="&#xd3;" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170 t-141.5 -483zM686 1579v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="&#xd4;" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170 t-141.5 -483zM492 1579v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="&#xd5;" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170 t-141.5 -483zM443 1581q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73z" /> +<glyph unicode="&#xd6;" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q306 0 479 -201.5t173 -550.5q0 -348 -174 -550.5t-480 -202.5q-305 0 -479 202.5t-174 552.5zM240 733q0 -314 140 -485.5t402 -171.5q264 0 403.5 170t139.5 487q0 316 -139.5 484.5t-401.5 168.5q-261 0 -402.5 -170 t-141.5 -483zM529 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM910 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="&#xd7;" d="M119 1130l57 58l408 -408l409 408l58 -58l-408 -407l406 -408l-58 -57l-407 408l-406 -408l-57 57l405 408z" /> +<glyph unicode="&#xd8;" horiz-adv-x="1565" d="M129 735q0 349 175.5 549.5t479.5 200.5q232 0 392 -121l108 152l72 -60l-111 -153q191 -207 191 -570q0 -348 -174 -550.5t-480 -202.5q-236 0 -395 120l-86 -120l-74 59l90 127q-188 200 -188 569zM240 733q0 -312 139 -483l739 1034q-133 102 -334 102 q-261 0 -402.5 -170t-141.5 -483zM444 182q133 -106 338 -106q264 0 403.5 170t139.5 487q0 315 -139 486z" /> +<glyph unicode="&#xd9;" horiz-adv-x="1473" d="M190 520v942h103v-946q0 -211 117 -328.5t331 -117.5q209 0 324 115.5t115 320.5v956h102v-946q0 -252 -146 -394t-407 -142q-254 0 -396.5 142.5t-142.5 397.5zM450 1890v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="&#xda;" horiz-adv-x="1473" d="M190 520v942h103v-946q0 -211 117 -328.5t331 -117.5q209 0 324 115.5t115 320.5v956h102v-946q0 -252 -146 -394t-407 -142q-254 0 -396.5 142.5t-142.5 397.5zM633 1579v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="&#xdb;" horiz-adv-x="1473" d="M190 520v942h103v-946q0 -211 117 -328.5t331 -117.5q209 0 324 115.5t115 320.5v956h102v-946q0 -252 -146 -394t-407 -142q-254 0 -396.5 142.5t-142.5 397.5zM444 1579v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207 q-108 -114 -221 -207h-70z" /> +<glyph unicode="&#xdc;" horiz-adv-x="1473" d="M190 520v942h103v-946q0 -211 117 -328.5t331 -117.5q209 0 324 115.5t115 320.5v956h102v-946q0 -252 -146 -394t-407 -142q-254 0 -396.5 142.5t-142.5 397.5zM481 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM862 1727q0 46 15.5 66t47.5 20 q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="&#xdd;" horiz-adv-x="1081" d="M0 1462h117l426 -800l428 800h110l-487 -897v-565h-105v557zM434 1579v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="&#xde;" horiz-adv-x="1198" d="M207 0v1462h102v-264h256q522 0 522 -420q0 -212 -144 -325t-408 -113h-226v-340h-102zM309 428h201q247 0 357 81.5t110 264.5q0 169 -104 250.5t-322 81.5h-242v-678z" /> +<glyph unicode="&#xdf;" horiz-adv-x="1194" d="M182 0v1206q0 173 103.5 267t292.5 94q188 0 285.5 -72.5t97.5 -210.5q0 -139 -139 -250q-81 -64 -110.5 -100.5t-29.5 -75.5q0 -44 14.5 -68t51.5 -57t102 -78q106 -75 151.5 -124.5t68 -103t22.5 -120.5q0 -156 -88 -241.5t-246 -85.5q-95 0 -174.5 18.5t-126.5 48.5 v107q65 -38 148.5 -62t152.5 -24q114 0 174.5 54.5t60.5 160.5q0 83 -39 144t-149 136q-127 87 -175 147t-48 146q0 60 32.5 110t106.5 108q74 57 106.5 105.5t32.5 106.5q0 93 -70 143t-202 50q-145 0 -226 -69t-81 -196v-1214h-99z" /> +<glyph unicode="&#xe0;" horiz-adv-x="1085" d="M98 289q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227zM203 285q0 -102 62.5 -158.5t176.5 -56.5 q174 0 274.5 99.5t100.5 276.5v107l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5zM255 1552v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="&#xe1;" horiz-adv-x="1085" d="M98 289q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227zM203 285q0 -102 62.5 -158.5t176.5 -56.5 q174 0 274.5 99.5t100.5 276.5v107l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5zM422 1241v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="&#xe2;" horiz-adv-x="1085" d="M98 289q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227zM203 285q0 -102 62.5 -158.5t176.5 -56.5 q174 0 274.5 99.5t100.5 276.5v107l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5zM251 1241v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="&#xe3;" horiz-adv-x="1085" d="M98 289q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227zM203 285q0 -102 62.5 -158.5t176.5 -56.5 q174 0 274.5 99.5t100.5 276.5v107l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5zM200 1243q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20 q-45 0 -75 -34.5t-48 -121.5h-73z" /> +<glyph unicode="&#xe4;" horiz-adv-x="1085" d="M98 289q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227zM203 285q0 -102 62.5 -158.5t176.5 -56.5 q174 0 274.5 99.5t100.5 276.5v107l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5zM282 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM663 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="&#xe5;" horiz-adv-x="1085" d="M98 289q0 159 132.5 247t383.5 93l207 6v72q0 155 -63 234t-203 79q-151 0 -313 -84l-37 86q179 84 354 84q179 0 267.5 -93t88.5 -290v-723h-73l-25 172h-8q-82 -105 -168.5 -148.5t-204.5 -43.5q-160 0 -249 82t-89 227zM203 285q0 -102 62.5 -158.5t176.5 -56.5 q174 0 274.5 99.5t100.5 276.5v107l-190 -8q-229 -11 -326.5 -71.5t-97.5 -188.5zM325 1456q0 94 60 152.5t157 58.5t157 -59t60 -152q0 -97 -60 -155t-157 -58t-157 58t-60 155zM405 1456q0 -66 37.5 -103.5t99.5 -37.5t99.5 37.5t37.5 103.5q0 64 -39 101.5t-98 37.5 q-62 0 -99.5 -38t-37.5 -101z" /> +<glyph unicode="&#xe6;" horiz-adv-x="1731" d="M98 289q0 154 125 243t377 97l201 6v72q0 155 -61.5 234t-198.5 79q-148 0 -305 -84l-37 86q173 84 346 84q261 0 325 -211q111 213 347 213q184 0 289.5 -134.5t105.5 -363.5v-80h-715q0 -460 348 -460q85 0 150 12t174 57v-90q-92 -41 -165 -55t-161 -14 q-295 0 -397 256q-68 -133 -168 -194.5t-252 -61.5q-156 0 -242 82.5t-86 226.5zM203 285q0 -102 61 -158.5t170 -56.5q169 0 266 99.5t97 276.5v107l-187 -8q-219 -11 -313 -71.5t-94 -188.5zM903 618h604q0 188 -77.5 295t-212.5 107q-284 0 -314 -402z" /> +<glyph unicode="&#xe7;" horiz-adv-x="973" d="M119 537q0 270 137 420.5t375 150.5q141 0 270 -49l-27 -88q-141 47 -245 47q-200 0 -303 -123.5t-103 -355.5q0 -220 103 -344.5t288 -124.5q148 0 275 53v-92q-104 -51 -273 -51q-233 0 -365 147t-132 410zM373 -393q30 -10 92 -10q78 0 119 28t41 80q0 94 -193 121 l93 174h96l-66 -117q168 -37 168 -174q0 -100 -67.5 -150.5t-188.5 -50.5q-68 0 -94 11v88z" /> +<glyph unicode="&#xe8;" horiz-adv-x="1124" d="M119 535q0 260 128 416.5t345 156.5q192 0 303 -134t111 -364v-80h-783q2 -224 104.5 -342t293.5 -118q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5q-237 0 -369.5 146t-132.5 409zM229 618h672q0 189 -82 295.5t-227 106.5q-157 0 -252 -103.5 t-111 -298.5zM302 1552v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="&#xe9;" horiz-adv-x="1124" d="M119 535q0 260 128 416.5t345 156.5q192 0 303 -134t111 -364v-80h-783q2 -224 104.5 -342t293.5 -118q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5q-237 0 -369.5 146t-132.5 409zM229 618h672q0 189 -82 295.5t-227 106.5q-157 0 -252 -103.5 t-111 -298.5zM452 1241v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="&#xea;" horiz-adv-x="1124" d="M119 535q0 260 128 416.5t345 156.5q192 0 303 -134t111 -364v-80h-783q2 -224 104.5 -342t293.5 -118q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5q-237 0 -369.5 146t-132.5 409zM229 618h672q0 189 -82 295.5t-227 106.5q-157 0 -252 -103.5 t-111 -298.5zM290 1241v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="&#xeb;" horiz-adv-x="1124" d="M119 535q0 260 128 416.5t345 156.5q192 0 303 -134t111 -364v-80h-783q2 -224 104.5 -342t293.5 -118q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5q-237 0 -369.5 146t-132.5 409zM229 618h672q0 189 -82 295.5t-227 106.5q-157 0 -252 -103.5 t-111 -298.5zM331 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM712 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="&#xec;" horiz-adv-x="463" d="M182 0v1087h99v-1087h-99zM-34 1552v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="&#xed;" horiz-adv-x="463" d="M182 0v1087h99v-1087h-99zM107 1241v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="&#xee;" horiz-adv-x="463" d="M182 0v1087h99v-1087h-99zM-58 1241v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="&#xef;" horiz-adv-x="463" d="M182 0v1087h99v-1087h-99zM-21 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM360 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="&#xf0;" horiz-adv-x="1174" d="M117 471q0 228 126.5 357.5t342.5 129.5q108 0 187.5 -33t148.5 -96l4 2q-64 270 -269 459l-270 -157l-49 77l244 146q-86 62 -199 119l45 81q147 -69 248 -145l225 137l49 -84l-202 -121q154 -151 230.5 -353t76.5 -431q0 -276 -124 -427.5t-349 -151.5 q-214 0 -339.5 130t-125.5 361zM221 463q0 -186 94.5 -289.5t268.5 -103.5q179 0 272.5 123t93.5 364q0 146 -97 228.5t-267 82.5q-185 0 -275 -100.5t-90 -304.5z" /> +<glyph unicode="&#xf1;" horiz-adv-x="1208" d="M182 0v1087h84l19 -149h6q106 170 377 170q370 0 370 -397v-711h-98v705q0 164 -69 238.5t-214 74.5q-195 0 -285.5 -98.5t-90.5 -319.5v-600h-99zM282 1243q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76 q-16 -116 -69 -177t-132 -61q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73z" /> +<glyph unicode="&#xf2;" horiz-adv-x="1200" d="M119 545q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z M335 1552v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="&#xf3;" horiz-adv-x="1200" d="M119 545q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z M499 1241v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="&#xf4;" horiz-adv-x="1200" d="M119 545q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z M309 1241v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="&#xf5;" horiz-adv-x="1200" d="M119 545q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z M264 1243q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73z" /> +<glyph unicode="&#xf6;" horiz-adv-x="1200" d="M119 545q0 266 129 414.5t354 148.5q224 0 351.5 -150.5t127.5 -412.5q0 -266 -129 -415.5t-356 -149.5q-143 0 -252 69t-167 198t-58 298zM223 545q0 -224 98.5 -349.5t278.5 -125.5t278.5 125.5t98.5 349.5q0 225 -99.5 349t-279.5 124t-277.5 -123.5t-97.5 -349.5z M346 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM727 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="&#xf7;" d="M111 682v82h948v-82h-948zM504 371q0 98 80 98q82 0 82 -98q0 -53 -23.5 -76t-58.5 -23q-34 0 -57 23t-23 76zM504 1075q0 99 80 99q82 0 82 -99q0 -52 -23.5 -75t-58.5 -23q-34 0 -57 23t-23 75z" /> +<glyph unicode="&#xf8;" horiz-adv-x="1200" d="M119 545q0 266 129 414.5t354 148.5q179 0 301 -104l96 124l74 -55l-104 -137q112 -147 112 -391q0 -266 -129 -415.5t-356 -149.5q-173 0 -291 98l-86 -113l-72 58l93 120q-121 153 -121 402zM223 545q0 -200 78 -322l543 705q-98 90 -246 90q-180 0 -277.5 -123.5 t-97.5 -349.5zM362 152q94 -82 238 -82q180 0 278.5 125.5t98.5 349.5q0 190 -72 309z" /> +<glyph unicode="&#xf9;" horiz-adv-x="1208" d="M170 377v710h98v-704q0 -164 69 -238.5t214 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-106 -170 -377 -170q-371 0 -371 397zM304 1552v17h142q26 -48 98.5 -142t142.5 -170v-16h-69q-96 79 -188.5 171.5t-125.5 139.5z" /> +<glyph unicode="&#xfa;" horiz-adv-x="1208" d="M170 377v710h98v-704q0 -164 69 -238.5t214 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-106 -170 -377 -170q-371 0 -371 397zM495 1241v16q73 79 144.5 171.5t97.5 140.5h141v-17q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="&#xfb;" horiz-adv-x="1208" d="M170 377v710h98v-704q0 -164 69 -238.5t214 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-106 -170 -377 -170q-371 0 -371 397zM313 1241v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="&#xfc;" horiz-adv-x="1208" d="M170 377v710h98v-704q0 -164 69 -238.5t214 -74.5q194 0 285.5 98t91.5 319v600h98v-1087h-84l-18 150h-6q-106 -170 -377 -170q-371 0 -371 397zM350 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM731 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86 q-63 0 -63 86z" /> +<glyph unicode="&#xfd;" horiz-adv-x="940" d="M0 1087h102l230 -610q105 -281 133 -379h6q42 129 137 385l230 604h102l-487 -1263q-59 -154 -99 -208t-93.5 -81t-129.5 -27q-57 0 -127 21v86q58 -16 125 -16q51 0 90 24t70.5 74.5t73 160t53.5 142.5zM361 1241v16q73 79 144.5 171.5t97.5 140.5h141v-17 q-36 -52 -122.5 -138t-190.5 -173h-70z" /> +<glyph unicode="&#xfe;" horiz-adv-x="1219" d="M182 -492v2048h99v-391l-7 -247h7q114 190 368 190q220 0 335.5 -144.5t115.5 -420.5q0 -268 -121.5 -415.5t-331.5 -147.5q-251 0 -366 188h-7l3 -84q4 -74 4 -162v-414h-99zM281 541q0 -255 85.5 -364t278.5 -109q167 0 258.5 124t91.5 347q0 479 -348 479 q-193 0 -279.5 -105t-86.5 -354v-18z" /> +<glyph unicode="&#xff;" horiz-adv-x="940" d="M0 1087h102l230 -610q105 -281 133 -379h6q42 129 137 385l230 604h102l-487 -1263q-59 -154 -99 -208t-93.5 -81t-129.5 -27q-57 0 -127 21v86q58 -16 125 -16q51 0 90 24t70.5 74.5t73 160t53.5 142.5zM214 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86 q-63 0 -63 86zM595 1389q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="&#x131;" horiz-adv-x="463" d="M182 0v1087h99v-1087h-99z" /> +<glyph unicode="&#x152;" horiz-adv-x="1839" d="M129 735q0 347 174.5 545.5t480.5 198.5q78 0 183 -17h747v-94h-655v-553h616v-94h-616v-627h655v-94h-756q-76 -16 -176 -16q-305 0 -479 200t-174 551zM240 733q0 -315 140.5 -484t401.5 -169q109 0 174 18v1266q-62 16 -172 16q-262 0 -403 -167.5t-141 -479.5z" /> +<glyph unicode="&#x153;" horiz-adv-x="1942" d="M119 545q0 266 129 414.5t354 148.5q151 0 251 -70t157 -209q110 279 399 279q192 0 303 -134t111 -364v-80h-762q2 -230 100.5 -345t276.5 -115q93 0 163.5 13t178.5 56v-90q-92 -40 -170 -54.5t-172 -14.5q-156 0 -266.5 67.5t-165.5 198.5q-59 -128 -158 -197 t-252 -69q-143 0 -252 69t-167 198t-58 298zM223 545q0 -224 98.5 -349.5t278.5 -125.5q174 0 265 122.5t91 352.5q0 224 -93 348.5t-265 124.5q-180 0 -277.5 -123.5t-97.5 -349.5zM1065 618h653q0 189 -82 295.5t-227 106.5q-155 0 -242 -104t-102 -298z" /> +<glyph unicode="&#x178;" horiz-adv-x="1081" d="M0 1462h117l426 -800l428 800h110l-487 -897v-565h-105v557zM288 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86zM669 1727q0 46 15.5 66t47.5 20q64 0 64 -86t-64 -86q-63 0 -63 86z" /> +<glyph unicode="&#x2c6;" horiz-adv-x="1182" d="M299 1241v16q62 67 131.5 156t110.5 156h98q68 -120 242 -312v-16h-70q-122 101 -221 207q-108 -114 -221 -207h-70z" /> +<glyph unicode="&#x2da;" horiz-adv-x="1182" d="M371 1456q0 94 60 152.5t157 58.5t157 -59t60 -152q0 -97 -60 -155t-157 -58t-157 58t-60 155zM451 1456q0 -66 37.5 -103.5t99.5 -37.5t99.5 37.5t37.5 103.5q0 64 -39 101.5t-98 37.5q-62 0 -99.5 -38t-37.5 -101z" /> +<glyph unicode="&#x2dc;" horiz-adv-x="1182" d="M283 1243q10 111 63 174.5t137 63.5q48 0 88 -25t82 -59q34 -28 66 -50t61 -22q46 0 77 36.5t48 119.5h76q-16 -116 -69 -177t-132 -61q-36 0 -75 18.5t-101 71.5q-32 26 -62.5 46t-62.5 20q-45 0 -75 -34.5t-48 -121.5h-73z" /> +<glyph unicode="&#x2000;" horiz-adv-x="953" /> +<glyph unicode="&#x2001;" horiz-adv-x="1907" /> +<glyph unicode="&#x2002;" horiz-adv-x="953" /> +<glyph unicode="&#x2003;" horiz-adv-x="1907" /> +<glyph unicode="&#x2004;" horiz-adv-x="635" /> +<glyph unicode="&#x2005;" horiz-adv-x="476" /> +<glyph unicode="&#x2006;" horiz-adv-x="317" /> +<glyph unicode="&#x2007;" horiz-adv-x="317" /> +<glyph unicode="&#x2008;" horiz-adv-x="238" /> +<glyph unicode="&#x2009;" horiz-adv-x="381" /> +<glyph unicode="&#x200a;" horiz-adv-x="105" /> +<glyph unicode="&#x2010;" horiz-adv-x="659" d="M92 512v82h475v-82h-475z" /> +<glyph unicode="&#x2011;" horiz-adv-x="659" d="M92 512v82h475v-82h-475z" /> +<glyph unicode="&#x2012;" horiz-adv-x="659" d="M92 512v82h475v-82h-475z" /> +<glyph unicode="&#x2013;" horiz-adv-x="1024" d="M82 512v82h860v-82h-860z" /> +<glyph unicode="&#x2014;" horiz-adv-x="2048" d="M82 512v82h1884v-82h-1884z" /> +<glyph unicode="&#x2018;" horiz-adv-x="297" d="M29 981q32 112 81.5 251t92.5 230h65q-30 -101 -64.5 -257t-45.5 -244h-117z" /> +<glyph unicode="&#x2019;" horiz-adv-x="297" d="M29 961q29 96 61 241.5t49 259.5h117l12 -20q-75 -265 -174 -481h-65z" /> +<glyph unicode="&#x201a;" horiz-adv-x="451" d="M68 -263q29 96 61 241.5t49 259.5h117l12 -20q-75 -265 -174 -481h-65z" /> +<glyph unicode="&#x201c;" horiz-adv-x="614" d="M29 981q32 112 81.5 251t92.5 230h65q-30 -101 -64.5 -257t-45.5 -244h-117zM346 981q34 120 83 255t91 226h66q-30 -98 -63 -248.5t-48 -252.5h-117z" /> +<glyph unicode="&#x201d;" horiz-adv-x="614" d="M29 961q29 96 61 241.5t49 259.5h117l12 -20q-75 -265 -174 -481h-65zM346 961q30 98 63 248.5t48 252.5h116l13 -20q-36 -128 -85 -261t-89 -220h-66z" /> +<glyph unicode="&#x201e;" horiz-adv-x="768" d="M68 -263q29 96 61 241.5t49 259.5h117l12 -20q-75 -265 -174 -481h-65zM385 -263q30 98 63 248.5t48 252.5h116l13 -20q-36 -128 -85 -261t-89 -220h-66z" /> +<glyph unicode="&#x2022;" horiz-adv-x="770" d="M231 748q0 89 40.5 134.5t113.5 45.5t113.5 -47t40.5 -133q0 -85 -41 -133t-113 -48t-113 47t-41 134z" /> +<glyph unicode="&#x2026;" horiz-adv-x="1466" d="M162 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98zM651 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98zM1141 78q0 98 80 98q82 0 82 -98t-82 -98q-80 0 -80 98z" /> +<glyph unicode="&#x202f;" horiz-adv-x="381" /> +<glyph unicode="&#x2039;" horiz-adv-x="524" d="M82 516v27l309 393l62 -43l-254 -363l254 -362l-62 -43z" /> +<glyph unicode="&#x203a;" horiz-adv-x="524" d="M72 168l254 362l-254 363l61 43l309 -391v-27l-309 -393z" /> +<glyph unicode="&#x2044;" horiz-adv-x="246" d="M-332 0l811 1462h94l-811 -1462h-94z" /> +<glyph unicode="&#x205f;" horiz-adv-x="476" /> +<glyph unicode="&#x2074;" horiz-adv-x="688" d="M25 827v60l407 581h96v-563h129v-78h-129v-241h-90v241h-413zM129 905h309v221q0 132 8 232q-6 -12 -21.5 -35.5t-295.5 -417.5z" /> +<glyph unicode="&#x20ac;" d="M74 528v82h172q-4 38 -4 113l4 102h-172v82h184q39 272 183 425t362 153q88 0 161 -17t148 -57l-39 -86q-132 72 -270 72q-174 0 -288 -125.5t-155 -364.5h502v-82h-510l-4 -104v-24q0 -65 4 -87h449v-82h-443q30 -217 147.5 -338.5t301.5 -121.5q148 0 287 65v-94 q-81 -34 -150.5 -46.5t-140.5 -12.5q-228 0 -367.5 140t-181.5 408h-180z" /> +<glyph unicode="&#x2122;" horiz-adv-x="1485" d="M10 1384v78h522v-78h-219v-643h-86v643h-217zM608 741v721h125l221 -606l224 606h125v-721h-86v398l4 207h-7l-227 -605h-74l-221 609h-6l4 -201v-408h-82z" /> +<glyph unicode="&#x2212;" d="M111 682v82h948v-82h-948z" /> +<glyph unicode="&#xe000;" horiz-adv-x="1085" d="M0 1085h1085v-1085h-1085v1085z" /> +<glyph unicode="&#xfb01;" horiz-adv-x="1077" d="M29 1001v58l202 37v84q0 200 73.5 293.5t240.5 93.5q90 0 180 -27l-23 -86q-80 25 -159 25q-116 0 -164.5 -68.5t-48.5 -222.5v-101h256v-86h-256v-1001h-99v1001h-202zM782 1389q0 96 63 96q31 0 48.5 -25t17.5 -71q0 -45 -17.5 -71t-48.5 -26q-63 0 -63 97zM796 0v1087 h99v-1087h-99z" /> +<glyph unicode="&#xfb02;" horiz-adv-x="1077" d="M29 1001v58l202 37v84q0 200 73.5 293.5t240.5 93.5q90 0 180 -27l-23 -86q-80 25 -159 25q-116 0 -164.5 -68.5t-48.5 -222.5v-101h256v-86h-256v-1001h-99v1001h-202zM796 0v1556h99v-1556h-99z" /> +<glyph unicode="&#xfb03;" horiz-adv-x="1692" d="M29 1001v58l202 37v84q0 200 73.5 293.5t240.5 93.5q90 0 180 -27l-23 -86q-80 25 -159 25q-116 0 -164.5 -68.5t-48.5 -222.5v-101h256v-86h-256v-1001h-99v1001h-202zM643 1001v58l202 37v84q0 200 73.5 293.5t240.5 93.5q90 0 180 -27l-23 -86q-80 25 -159 25 q-116 0 -164.5 -68.5t-48.5 -222.5v-101h256v-86h-256v-1001h-99v1001h-202zM1397 1389q0 96 63 96q31 0 48.5 -25t17.5 -71q0 -45 -17.5 -71t-48.5 -26q-63 0 -63 97zM1411 0v1087h99v-1087h-99z" /> +<glyph unicode="&#xfb04;" horiz-adv-x="1692" d="M29 1001v58l202 37v84q0 200 73.5 293.5t240.5 93.5q90 0 180 -27l-23 -86q-80 25 -159 25q-116 0 -164.5 -68.5t-48.5 -222.5v-101h256v-86h-256v-1001h-99v1001h-202zM643 1001v58l202 37v84q0 200 73.5 293.5t240.5 93.5q90 0 180 -27l-23 -86q-80 25 -159 25 q-116 0 -164.5 -68.5t-48.5 -222.5v-101h256v-86h-256v-1001h-99v1001h-202zM1411 0v1556h99v-1556h-99z" /> +</font> +</defs></svg> +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Light-webfont.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.svg b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.svg @@ -0,0 +1,252 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata> +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom +</metadata> +<defs> +<font id="OpenSansLightItalic" horiz-adv-x="1128" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="&#x09;" horiz-adv-x="532" /> +<glyph unicode="&#xa0;" horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="502" d="M80 57q0 56 25 88.5t69 32.5q66 0 66 -72q0 -53 -25 -87.5t-68 -34.5q-67 0 -67 73zM186 377l203 1085h119l-260 -1085h-62z" /> +<glyph unicode="&#x22;" horiz-adv-x="721" d="M248 934l80 528h127l-146 -528h-61zM578 934l79 528h127l-145 -528h-61z" /> +<glyph unicode="#" horiz-adv-x="1323" d="M82 451l8 79h299l119 398h-297l8 80h311l134 454h90l-136 -454h365l135 454h86l-135 -454h285l-8 -80h-302l-118 -398h303l-8 -79h-320l-133 -451h-90l135 451h-360l-134 -451h-88l134 451h-283zM475 530h363l120 398h-362z" /> +<glyph unicode="$" d="M141 182v94q65 -34 153.5 -53.5t160.5 -19.5l110 512q-110 53 -153 91t-66.5 87.5t-23.5 116.5q0 155 105.5 250.5t272.5 99.5l41 192h80l-41 -192q149 -5 277 -68l-35 -78q-110 61 -256 70l-109 -514q124 -60 172.5 -99.5t73.5 -88.5t25 -115q0 -151 -110.5 -243 t-297.5 -103l-53 -240h-82l51 240q-79 2 -158 18t-137 43zM410 1018q0 -78 37 -128.5t137 -96.5l102 491q-134 -9 -205 -80t-71 -186zM537 203q142 7 223.5 74.5t81.5 183.5q0 76 -48 129.5t-157 97.5z" /> +<glyph unicode="%" horiz-adv-x="1556" d="M145 862q0 160 52 312t138 229.5t193 77.5q232 0 232 -283q0 -175 -50 -327t-136 -230t-197 -78q-112 0 -172 75.5t-60 223.5zM213 0l1135 1462h110l-1139 -1462h-106zM231 868q0 -115 41 -173t113 -58q84 0 148.5 72t102.5 204t38 277q0 109 -36 163t-114 54 q-79 0 -145 -71.5t-107 -203t-41 -264.5zM905 276q0 160 52 312t138 229.5t193 77.5q121 0 176.5 -71.5t55.5 -211.5q0 -175 -50 -327t-136 -230t-197 -78q-112 0 -172 75.5t-60 223.5zM991 283q0 -116 41 -174t113 -58q130 0 209.5 166.5t79.5 386.5q0 109 -36 163t-114 54 q-80 0 -146.5 -72.5t-106.5 -202.5t-40 -263z" /> +<glyph unicode="&#x26;" horiz-adv-x="1331" d="M78 324q0 162 99 277.5t325 215.5l-41 67q-78 128 -78 251q0 157 101 253.5t264 96.5q145 0 227 -76.5t82 -206.5q0 -85 -41 -154t-121 -128t-256 -138l330 -463q73 75 135.5 176.5t91.5 186.5h111q-102 -247 -285 -436l184 -246h-123l-131 184q-121 -108 -242 -156 t-266 -48q-167 0 -266.5 94t-99.5 250zM176 328q0 -119 78 -192t211 -73q108 0 211.5 42.5t222.5 146.5l-352 493q-164 -79 -232 -134.5t-103.5 -124t-35.5 -158.5zM485 1135q0 -132 109 -281q203 89 279.5 163.5t76.5 182.5q0 91 -56.5 143t-145.5 52q-125 0 -194 -68 t-69 -192z" /> +<glyph unicode="'" horiz-adv-x="403" d="M254 934l80 528h127l-146 -528h-61z" /> +<glyph unicode="(" horiz-adv-x="526" d="M104 270q0 343 122 633t382 559h105q-259 -276 -384.5 -568t-125.5 -618q0 -317 127 -600h-80q-146 262 -146 594z" /> +<glyph unicode=")" horiz-adv-x="526" d="M-156 -324q257 274 383.5 566.5t126.5 619.5q0 148 -28.5 294t-98.5 306h80q146 -262 146 -594q0 -345 -123.5 -636t-380.5 -556h-105z" /> +<glyph unicode="*" horiz-adv-x="1137" d="M233 1217l39 102l394 -168l47 408l121 -19l-109 -405l438 8l-8 -107l-416 29l181 -401l-115 -37l-135 417l-285 -348l-78 78l318 318z" /> +<glyph unicode="+" d="M162 672v100h401v404h101v-404h401v-100h-401v-400h-101v400h-401z" /> +<glyph unicode="," horiz-adv-x="451" d="M-90 -264q79 132 141 271t88 231h111l8 -23q-34 -92 -114 -233.5t-160 -245.5h-74z" /> +<glyph unicode="-" horiz-adv-x="629" d="M82 502l18 90h457l-16 -90h-459z" /> +<glyph unicode="." horiz-adv-x="485" d="M82 55q0 56 25 88.5t69 32.5q66 0 66 -72q0 -53 -25 -87.5t-67 -34.5q-68 0 -68 73z" /> +<glyph unicode="/" horiz-adv-x="641" d="M-100 0l815 1462h112l-817 -1462h-110z" /> +<glyph unicode="0" d="M139 494q0 186 44.5 381.5t124 334t187 207t240.5 68.5q340 0 340 -469q0 -201 -41 -405t-116.5 -346t-183.5 -213.5t-242 -71.5q-176 0 -264.5 126.5t-88.5 387.5zM242 504q0 -222 62.5 -329t197.5 -107q139 0 244 112t166 337t61 489q0 199 -59.5 295t-190.5 96 q-134 0 -241.5 -113t-173.5 -329t-66 -451z" /> +<glyph unicode="1" d="M354 1204l406 258h90l-313 -1462h-105l225 1055q19 92 74 293q-42 -36 -75.5 -61t-249.5 -161z" /> +<glyph unicode="2" d="M39 0l22 104l449 402q198 177 284 276.5t126.5 186.5t40.5 180q0 112 -66 178t-197 66q-176 0 -333 -129l-54 73q180 146 394 146q173 0 268.5 -85t95.5 -237q0 -110 -43.5 -208.5t-141.5 -211.5t-311 -303l-383 -338v-4h736l-17 -96h-870z" /> +<glyph unicode="3" d="M55 53v101q172 -86 344 -86q197 0 303.5 89.5t106.5 252.5q0 145 -89 223t-247 78h-117l21 96h110q209 0 333 95.5t124 258.5q0 114 -63.5 175t-188.5 61q-167 0 -344 -131l-49 75q84 67 188 104.5t218 37.5q161 0 252.5 -82.5t91.5 -226.5q0 -162 -106 -275t-286 -143 v-4q117 -24 185.5 -115.5t68.5 -226.5q0 -134 -64 -233t-179.5 -148t-274.5 -49q-96 0 -184.5 20.5t-153.5 52.5z" /> +<glyph unicode="4" d="M23 371l20 96l881 1010h118l-215 -1018h265l-21 -88h-264l-80 -371h-96l80 371h-688zM150 459h579q79 369 119 558.5t86 354.5h-4q-66 -91 -129 -166z" /> +<glyph unicode="5" d="M88 51v107q170 -90 340 -90q208 0 328.5 114.5t120.5 313.5q0 140 -85 219.5t-225 79.5q-133 0 -243 -41l-66 49l193 659h624l-18 -96h-541l-149 -516q98 29 215 29q188 0 292.5 -102t104.5 -279q0 -237 -148 -377.5t-407 -140.5q-84 0 -177.5 20t-158.5 51z" /> +<glyph unicode="6" d="M170 428q0 283 105 544.5t269.5 385t383.5 123.5q123 0 182 -21l-18 -90q-86 23 -170 23q-233 0 -393.5 -174t-233.5 -502h8q68 94 164 143t211 49q161 0 250.5 -100.5t89.5 -282.5q0 -156 -60 -281t-171 -195t-257 -70q-171 0 -265.5 119t-94.5 329zM270 414 q0 -164 72.5 -255t200.5 -91q112 0 196.5 58.5t130 162t45.5 229.5q0 146 -67 224.5t-195 78.5q-81 0 -154 -31.5t-129 -87t-78 -115t-22 -173.5z" /> +<glyph unicode="7" d="M244 0l796 1366h-766l23 96h858l-20 -110l-779 -1352h-112z" /> +<glyph unicode="8" d="M98 326q0 159 100.5 268.5t321.5 187.5q-100 72 -144 152t-44 180q0 159 114 265t291 106q163 0 258 -85t95 -229q0 -138 -84 -234.5t-285 -172.5q130 -78 190 -170.5t60 -208.5t-58 -208t-165.5 -144.5t-260.5 -52.5q-178 0 -283.5 92.5t-105.5 253.5zM201 340 q0 -136 77.5 -206.5t219.5 -70.5q168 0 270 91t102 233q0 104 -62 189t-198 157q-218 -73 -313.5 -167.5t-95.5 -225.5zM428 1114q0 -91 41.5 -159t157.5 -142q192 62 279 144t87 206q0 109 -70.5 172.5t-195.5 63.5q-130 0 -214.5 -82t-84.5 -203z" /> +<glyph unicode="9" d="M115 2v90q87 -29 192 -29q474 0 627 674h-8q-140 -192 -367 -192q-162 0 -255 105t-93 284q0 155 59.5 281t170.5 196t257 70q174 0 267.5 -115.5t93.5 -333.5q0 -288 -101.5 -548t-263.5 -382t-393 -122q-114 0 -186 22zM313 942q0 -145 67.5 -225t192.5 -80 q83 0 157.5 32.5t129 87.5t76.5 114t22 176q0 166 -71 256t-201 90q-112 0 -197.5 -58.5t-130.5 -162.5t-45 -230z" /> +<glyph unicode=":" horiz-adv-x="485" d="M102 55q0 56 25.5 88.5t69.5 32.5q65 0 65 -72q0 -55 -25.5 -88.5t-66.5 -33.5q-68 0 -68 73zM260 989q0 57 25.5 89t68.5 32q66 0 66 -72q0 -55 -25 -89t-67 -34q-68 0 -68 74z" /> +<glyph unicode=";" horiz-adv-x="485" d="M-53 -264q79 132 141 271t88 231h111l8 -23q-35 -96 -118.5 -242t-156.5 -237h-73zM266 989q0 57 25.5 89t68.5 32q66 0 66 -72q0 -55 -25 -89t-67 -34q-68 0 -68 74z" /> +<glyph unicode="&#x3c;" d="M137 676v74l914 471v-103l-801 -399l801 -350v-107z" /> +<glyph unicode="=" d="M168 461v98h903v-98h-903zM168 885v100h903v-100h-903z" /> +<glyph unicode="&#x3e;" d="M170 262v107l801 350l-801 399v103l915 -471v-74z" /> +<glyph unicode="?" horiz-adv-x="799" d="M170 59q0 56 25 88.5t69 32.5q66 0 66 -71q0 -54 -24.5 -88.5t-67.5 -34.5q-68 0 -68 73zM182 1376q85 49 171.5 78t187.5 29q159 0 250.5 -84.5t91.5 -229.5q0 -127 -66 -234t-231 -226q-85 -61 -132.5 -108.5t-73 -95t-46.5 -143.5h-92l6 29q29 132 82 206.5t157 147.5 q118 84 175 145.5t86.5 127.5t29.5 141q0 108 -67.5 170t-182.5 62q-139 0 -307 -101z" /> +<glyph unicode="@" horiz-adv-x="1724" d="M125 508q0 276 121.5 493.5t337 337t473.5 119.5q189 0 330.5 -72.5t221 -213t79.5 -314.5q0 -179 -56 -323.5t-154.5 -227t-211.5 -82.5q-98 0 -154.5 55t-56.5 144h-4q-54 -97 -132.5 -148t-168.5 -51q-112 0 -178 73t-66 202q0 156 63 283t178 198.5t261 71.5 q122 0 252 -52l-84 -315q-39 -140 -39 -221q0 -71 34.5 -111.5t100.5 -40.5q86 0 160 73.5t117.5 198t43.5 251.5q0 156 -65 277t-187 188t-292 67q-235 0 -424.5 -108.5t-295.5 -304t-106 -439.5q0 -288 155 -449t435 -161q207 0 420 82v-90q-210 -82 -428 -82 q-203 0 -357.5 82.5t-238.5 239t-84 370.5zM610 506q0 -92 40.5 -142.5t113.5 -50.5q101 0 180.5 89t124.5 255l78 289q-66 23 -139 23q-113 0 -204.5 -59t-142.5 -165.5t-51 -238.5z" /> +<glyph unicode="A" horiz-adv-x="1059" d="M-111 0l822 1468h67l201 -1468h-105l-69 520h-512l-287 -520h-117zM344 612h449l-39 291q-31 242 -39 402q-30 -63 -64.5 -130t-306.5 -563z" /> +<glyph unicode="B" horiz-adv-x="1202" d="M102 0l310 1462h379q190 0 290.5 -84t100.5 -241q0 -153 -90 -249t-254 -124v-4q125 -31 188.5 -113.5t63.5 -204.5q0 -205 -140.5 -323.5t-390.5 -118.5h-457zM223 90h342q201 0 309.5 87.5t108.5 256.5q0 145 -90 216t-275 71h-260zM377 811h278q206 0 313 81t107 238 q0 119 -78 180.5t-229 61.5h-272z" /> +<glyph unicode="C" horiz-adv-x="1169" d="M170 535q0 266 104.5 488t284.5 341t402 119q177 0 307 -68l-45 -90q-55 30 -124.5 47t-137.5 17q-197 0 -351.5 -104.5t-245 -304.5t-90.5 -441q0 -225 110.5 -346t317.5 -121q140 0 304 51v-94q-156 -49 -316 -49q-252 0 -386 145t-134 410z" /> +<glyph unicode="D" horiz-adv-x="1350" d="M102 0l310 1462h305q282 0 426.5 -147.5t144.5 -435.5q0 -253 -109.5 -461.5t-300.5 -313t-446 -104.5h-330zM221 90h209q226 0 394.5 94.5t261 275.5t92.5 412q0 498 -476 498h-206z" /> +<glyph unicode="E" horiz-adv-x="1067" d="M102 0l310 1462h727l-21 -94h-624l-117 -553h590l-21 -94h-588l-135 -627h627l-21 -94h-727z" /> +<glyph unicode="F" horiz-adv-x="981" d="M102 0l310 1462h708l-20 -94h-604l-134 -620h570l-21 -95h-569l-137 -653h-103z" /> +<glyph unicode="G" horiz-adv-x="1374" d="M170 547q0 265 105 483.5t283.5 335.5t395.5 117q113 0 203 -19t184 -59l-38 -94q-110 46 -189.5 62t-167.5 16q-184 0 -339 -107.5t-244 -301.5t-89 -433q0 -229 114.5 -352t326.5 -123q155 0 309 47l117 526h-303l18 90h406l-150 -682q-211 -73 -405 -73 q-257 0 -397 146t-140 421z" /> +<glyph unicode="H" horiz-adv-x="1366" d="M102 0l310 1462h102l-139 -649h760l137 649h100l-309 -1462h-100l151 719h-760l-149 -719h-103z" /> +<glyph unicode="I" horiz-adv-x="504" d="M102 0l310 1462h98l-309 -1462h-99z" /> +<glyph unicode="J" horiz-adv-x="477" d="M-324 -336l11 92q57 -20 137 -20q213 0 262 241l309 1485h105l-314 -1491q-35 -170 -125 -250.5t-241 -80.5q-48 0 -88 8t-56 16z" /> +<glyph unicode="K" horiz-adv-x="1122" d="M102 0l310 1462h102l-158 -723l133 121l680 602h138l-699 -610l371 -852h-111l-342 788l-190 -153l-131 -635h-103z" /> +<glyph unicode="L" horiz-adv-x="938" d="M102 0l310 1462h102l-289 -1366h621l-23 -96h-721z" /> +<glyph unicode="M" horiz-adv-x="1669" d="M109 0l309 1462h143l205 -1257h6l733 1257h150l-301 -1462h-101l191 901q79 369 100 447h-6l-780 -1348h-51l-222 1348h-6q-20 -154 -78 -426l-196 -922h-96z" /> +<glyph unicode="N" horiz-adv-x="1372" d="M102 0l310 1462h80l522 -1294h8q23 176 74 416l188 878h94l-309 -1462h-86l-516 1284h-8q-23 -149 -48 -273t-214 -1011h-95z" /> +<glyph unicode="O" horiz-adv-x="1464" d="M172 559q0 262 93 477.5t255 331t373 115.5q247 0 378.5 -148.5t131.5 -423.5q0 -255 -94 -481.5t-252 -338t-365 -111.5q-250 0 -385 149t-135 430zM276 573q0 -245 109.5 -373t319.5 -128q169 0 300 98.5t210 300t79 430.5q0 240 -104.5 364t-310.5 124 q-174 0 -308.5 -101t-214.5 -298t-80 -417z" /> +<glyph unicode="P" horiz-adv-x="1145" d="M102 0l310 1462h315q202 0 310 -92.5t108 -267.5q0 -500 -610 -500h-201l-129 -602h-103zM350 694h191q252 0 373.5 96.5t121.5 305.5q0 274 -329 274h-211z" /> +<glyph unicode="Q" horiz-adv-x="1464" d="M172 559q0 262 93 477.5t255 331t373 115.5q247 0 378.5 -148.5t131.5 -423.5q0 -216 -70 -418t-186.5 -324t-274.5 -167l267 -350h-142l-231 332l-74 -4q-250 0 -385 149t-135 430zM276 573q0 -245 109.5 -373t319.5 -128q169 0 300 98.5t210 300t79 430.5 q0 240 -104.5 364t-310.5 124q-174 0 -308.5 -101t-214.5 -298t-80 -417z" /> +<glyph unicode="R" horiz-adv-x="1145" d="M102 0l310 1462h303q430 0 430 -360q0 -182 -103.5 -303t-281.5 -152q201 -591 221 -647h-111l-211 633h-323l-131 -633h-103zM358 725h252q208 0 317 95.5t109 281.5q0 268 -329 268h-211z" /> +<glyph unicode="S" horiz-adv-x="1020" d="M37 55v109q163 -92 348 -92q188 0 295.5 86.5t107.5 232.5q0 61 -17 104.5t-52.5 78.5t-91 68t-131.5 75q-150 76 -209.5 164t-59.5 206t59 207.5t165 139t237 49.5q99 0 180 -17.5t168 -60.5l-32 -94q-66 40 -151.5 63t-164.5 23q-163 0 -259.5 -82.5t-96.5 -218.5 q0 -103 49 -170t182 -133q154 -79 213.5 -130t89 -113t29.5 -147q0 -126 -65.5 -224.5t-179.5 -148.5t-269 -50q-88 0 -172.5 17t-171.5 58z" /> +<glyph unicode="T" horiz-adv-x="985" d="M193 1368l20 94h973l-19 -94h-440l-289 -1368h-102l289 1368h-432z" /> +<glyph unicode="U" horiz-adv-x="1370" d="M176 381q0 83 27 201l186 880h103l-193 -899q-20 -89 -20 -184q0 -309 342 -309q195 0 307.5 96.5t158.5 318.5l207 977h101l-207 -977q-58 -270 -197 -387.5t-375 -117.5q-440 0 -440 401z" /> +<glyph unicode="V" horiz-adv-x="1079" d="M201 1462h100l117 -950q26 -217 35 -365h4q51 111 124 247l572 1068h117l-799 -1462h-88z" /> +<glyph unicode="W" horiz-adv-x="1702" d="M238 1462h100l47 -1031l4 -165l-2 -86h6q85 226 170 398l434 884h105l61 -878q19 -266 19 -410h6q30 86 61.5 163t493.5 1125h108q-169 -365 -330.5 -731t-328.5 -731h-78l-78 1075q-11 142 -11 219l1 47h-8q-27 -76 -62 -153.5t-563 -1187.5h-82z" /> +<glyph unicode="X" horiz-adv-x="971" d="M-135 0l608 766l-272 696h106l240 -626l483 626h119l-555 -719l285 -743h-107l-254 678l-526 -678h-127z" /> +<glyph unicode="Y" horiz-adv-x="965" d="M193 1462h100l201 -817l544 817h117l-631 -932l-108 -530h-105l119 545z" /> +<glyph unicode="Z" d="M-12 0l22 92l1069 1276h-764l23 94h887l-19 -88l-1069 -1280h799l-23 -94h-925z" /> +<glyph unicode="[" horiz-adv-x="537" d="M-57 -324l376 1786h429l-19 -90h-330l-340 -1605h330l-20 -91h-426z" /> +<glyph unicode="\" horiz-adv-x="641" d="M209 1462h86l242 -1462h-82z" /> +<glyph unicode="]" horiz-adv-x="537" d="M-176 -324l18 91h330l340 1605h-330l21 90h426l-377 -1786h-428z" /> +<glyph unicode="^" horiz-adv-x="1047" d="M70 569l587 906h91l260 -906h-105l-217 809l-500 -809h-116z" /> +<glyph unicode="_" horiz-adv-x="801" d="M-182 -291l18 86h807l-18 -86h-807z" /> +<glyph unicode="`" horiz-adv-x="1135" d="M487 1548v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="a" horiz-adv-x="1133" d="M102 354q0 197 75 376t200.5 276.5t277.5 97.5q232 0 279 -219h6l59 202h80l-229 -1087h-82l45 274h-6q-84 -142 -187 -218t-237 -76q-281 0 -281 374zM205 365q0 -152 50 -223.5t151 -71.5q89 0 177.5 62t159 166t107.5 230t37 213q0 79 -26 141.5t-77 99t-127 36.5 q-124 0 -224 -82t-164 -245.5t-64 -325.5z" /> +<glyph unicode="b" horiz-adv-x="1151" d="M76 0l327 1556h95q-131 -628 -162 -751h6q93 156 199 229.5t231 73.5q281 0 281 -375q0 -203 -76 -380t-201 -273t-276 -96q-113 0 -186 59t-97 166h-6l-55 -209h-80zM268 346q0 -129 64 -202.5t166 -73.5q124 0 224 83t164 245t64 325q0 152 -49 223.5t-151 71.5 q-91 0 -180 -61.5t-160.5 -169.5t-106.5 -235t-35 -206z" /> +<glyph unicode="c" horiz-adv-x="887" d="M102 397q0 193 73.5 361.5t198.5 257t290 88.5q134 0 241 -43l-28 -90q-107 47 -218 47q-129 0 -232.5 -77t-162.5 -222t-59 -320q0 -158 73.5 -243.5t208.5 -85.5q71 0 131.5 13t131.5 46v-92q-116 -57 -273 -57q-174 0 -274.5 110.5t-100.5 306.5z" /> +<glyph unicode="d" horiz-adv-x="1133" d="M102 354q0 193 71.5 370t197.5 278.5t284 101.5q230 0 279 -219h4q12 66 143 671h99l-330 -1556h-82l45 274h-6q-173 -294 -424 -294q-281 0 -281 374zM205 365q0 -295 201 -295q89 0 178.5 62.5t160 168t106.5 231t36 209.5q0 126 -61.5 201.5t-168.5 75.5 q-124 0 -224 -83t-164 -242.5t-64 -327.5z" /> +<glyph unicode="e" horiz-adv-x="928" d="M102 395q0 181 71 347t195.5 264t274.5 98q114 0 182 -61t68 -166q0 -181 -163.5 -276t-485.5 -95h-33q-6 -44 -6 -98q0 -165 74 -251.5t213 -86.5q132 0 276 73v-94q-140 -69 -299 -69q-173 0 -270 109.5t-97 305.5zM225 594h49q517 0 517 270q0 67 -43.5 110.5 t-116.5 43.5q-131 0 -243.5 -115.5t-162.5 -308.5z" /> +<glyph unicode="f" horiz-adv-x="578" d="M-233 -383q53 -16 100 -16q88 0 134 53t75 186l246 1166h-205l14 67l205 14l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-25 -80q-87 27 -147 27q-96 0 -153.5 -53.5t-84.5 -178.5l-35 -164h248l-16 -81h-248l-252 -1190q-33 -161 -104 -234.5t-195 -73.5 q-48 0 -102 19v90z" /> +<glyph unicode="g" horiz-adv-x="1040" d="M-88 -217q0 236 309 334q-78 42 -78 123q0 123 191 202q-71 36 -110.5 105.5t-39.5 157.5q0 111 53.5 204t148 146t206.5 53q69 0 147 -21h361l-17 -79l-243 -11q26 -28 43.5 -84t17.5 -114q0 -109 -54.5 -206.5t-148 -145.5t-213.5 -48q-63 0 -77 9q-80 -33 -124 -73 t-44 -81t31.5 -64.5t113.5 -31.5l121 -11q346 -31 346 -264q0 -112 -65 -197.5t-187 -131.5t-291 -46q-186 0 -291.5 72t-105.5 203zM14 -207q0 -101 81 -150t224 -49q203 0 317 74.5t114 204.5q0 85 -62.5 130.5t-218.5 57.5l-160 15q-157 -45 -226 -114.5t-69 -168.5z M285 711q0 -112 58.5 -170t164.5 -58q88 0 154 37t102.5 114t36.5 169q0 104 -56 161.5t-157 57.5q-93 0 -161 -43t-105 -116t-37 -152z" /> +<glyph unicode="h" horiz-adv-x="1143" d="M76 0l332 1556h96l-86 -411q-44 -200 -66 -279h6q78 113 186.5 175.5t229.5 62.5q124 0 192 -65t68 -183q0 -70 -24 -182l-148 -674h-98l149 692q21 92 21 156q0 80 -43.5 125t-134.5 45q-112 0 -210.5 -67t-166 -188t-103.5 -286l-102 -477h-98z" /> +<glyph unicode="i" horiz-adv-x="475" d="M76 0l231 1087h96l-229 -1087h-98zM350 1366q0 55 22 88t60 33q57 0 57 -72q0 -57 -22 -90t-57 -33q-29 0 -44.5 19.5t-15.5 54.5z" /> +<glyph unicode="j" horiz-adv-x="475" d="M-279 -381q47 -22 113 -22q82 0 128.5 51.5t72.5 177.5l266 1261h96l-268 -1271q-35 -165 -106.5 -236.5t-188.5 -71.5q-62 0 -113 19v92zM350 1366q0 55 22 88t60 33q57 0 57 -72q0 -57 -22 -90t-57 -33q-29 0 -44.5 19.5t-15.5 54.5z" /> +<glyph unicode="k" horiz-adv-x="944" d="M76 0l330 1556h96l-166 -780l-70 -299h4l609 610h125l-474 -469l297 -618h-106l-264 559l-205 -188l-80 -371h-96z" /> +<glyph unicode="l" horiz-adv-x="475" d="M76 0l334 1556h94l-334 -1556h-94z" /> +<glyph unicode="m" horiz-adv-x="1751" d="M72 0l231 1087h80l-33 -210h6q80 113 181.5 170t212.5 57q106 0 163 -67t60 -195h6q77 129 181 195.5t222 66.5q117 0 182.5 -61.5t65.5 -176.5q0 -29 -2.5 -56.5t-19.5 -119.5l-152 -690h-100l149 680q25 120 25 176q0 77 -43 119.5t-119 42.5q-157 0 -277.5 -137.5 t-168.5 -362.5l-109 -518h-102l147 674q25 125 25 162q0 182 -154 182q-106 0 -200 -67.5t-159 -188.5t-100 -287l-100 -475h-98z" /> +<glyph unicode="n" horiz-adv-x="1143" d="M76 0l231 1087h82l-37 -221h6q164 238 416 238q130 0 195 -64t65 -184q0 -70 -24 -182l-148 -674h-98l149 692q21 92 21 156q0 80 -43.5 125t-134.5 45q-112 0 -210.5 -67t-166 -187.5t-103.5 -286.5l-102 -477h-98z" /> +<glyph unicode="o" horiz-adv-x="1124" d="M98 403q0 191 73 358t197 257t281 90q180 0 278.5 -108.5t98.5 -299.5q0 -197 -71.5 -368.5t-195.5 -261.5t-286 -90q-184 0 -279.5 109.5t-95.5 313.5zM201 408q0 -342 282 -342q127 0 225.5 77.5t157 228t58.5 330.5q0 154 -73 237t-210 83q-124 0 -223 -78.5 t-158 -225t-59 -310.5z" /> +<glyph unicode="p" horiz-adv-x="1149" d="M-33 -492l336 1579h82l-45 -274h6q91 153 195.5 224t228.5 71q135 0 208 -92.5t73 -282.5q0 -195 -72 -371t-197.5 -277t-283.5 -101q-230 0 -279 219h-4q-13 -72 -149 -695h-99zM266 346q0 -125 61.5 -200.5t168.5 -75.5q124 0 225 84t164 243.5t63 325.5 q0 295 -200 295q-87 0 -174 -58.5t-161.5 -167.5t-110.5 -237.5t-36 -208.5z" /> +<glyph unicode="q" horiz-adv-x="1157" d="M98 354q0 201 75.5 379t200.5 274.5t277 96.5q109 0 183.5 -58t99.5 -167h6l55 208h80l-327 -1556h-95l98 470l64 282h-6q-93 -156 -199 -229.5t-231 -73.5q-281 0 -281 374zM201 365q0 -143 45.5 -219t154.5 -76q92 0 182 62.5t160.5 171.5t105 236.5t34.5 200.5 q0 130 -63.5 203.5t-166.5 73.5q-124 0 -224 -83t-164 -245t-64 -325z" /> +<glyph unicode="r" horiz-adv-x="752" d="M72 0l231 1087h80l-29 -204h6q73 94 123 135.5t106.5 64.5t123.5 23q69 0 123 -14l-21 -93q-47 15 -113 15q-94 0 -179 -64t-153 -192t-100 -277l-100 -481h-98z" /> +<glyph unicode="s" horiz-adv-x="827" d="M25 55v107q74 -46 153 -71t148 -25q138 0 211 57.5t73 163.5q0 42 -15.5 74t-50 61.5t-132.5 85.5q-148 80 -200 145.5t-52 159.5q0 128 98.5 209.5t259.5 81.5q75 0 158.5 -17.5t140.5 -46.5l-35 -88q-136 64 -264 64q-116 0 -186 -53t-70 -138q0 -55 17 -88t60.5 -68.5 t119.5 -76.5q114 -63 161.5 -103.5t70 -86.5t22.5 -107q0 -144 -103 -229.5t-280 -85.5q-173 0 -305 75z" /> +<glyph unicode="t" horiz-adv-x="616" d="M113 1006l14 67l184 17l97 253h55l-55 -256h286l-18 -81h-283l-135 -635q-22 -99 -22 -164q0 -139 126 -139q68 0 152 26v-86q-101 -28 -170 -28q-99 0 -153 54.5t-54 158.5q0 73 29 206l129 607h-182z" /> +<glyph unicode="u" horiz-adv-x="1143" d="M109 227q0 60 22 170l150 690h100l-152 -698q-22 -106 -22 -158q0 -74 47.5 -117.5t138.5 -43.5q110 0 207.5 65.5t164 187t99.5 279.5l105 485h98l-231 -1087h-80l28 205h-6q-167 -221 -403 -221q-131 0 -198.5 62t-67.5 181z" /> +<glyph unicode="v" horiz-adv-x="895" d="M104 1087h101l108 -735q26 -165 33 -254h6q51 115 129 256l406 733h102l-600 -1087h-113z" /> +<glyph unicode="w" horiz-adv-x="1393" d="M121 1087h92l13 -821l-3 -157h6q61 134 150 297l373 681h77l64 -681q14 -147 14 -297h6l24 61l101 236l320 681h96l-508 -1087h-108l-60 686q-14 224 -14 266h-6q-34 -92 -144 -290l-356 -662h-117z" /> +<glyph unicode="x" horiz-adv-x="922" d="M-72 0l471 559l-245 528h100l207 -462l373 462h120l-448 -534l258 -553h-98l-224 483l-393 -483h-121z" /> +<glyph unicode="y" horiz-adv-x="920" d="M-217 -379q71 -27 137 -27q80 0 147 49.5t130 164.5t100 184l-174 1095h100l82 -548q51 -351 55 -449h11q43 105 186 367l348 630h103l-713 -1290q-72 -127 -122.5 -178t-114 -81t-146.5 -30q-68 0 -129 21v92z" /> +<glyph unicode="z" horiz-adv-x="887" d="M-29 0l15 72l776 932h-543l17 83h659l-18 -83l-762 -920h602l-17 -84h-729z" /> +<glyph unicode="{" horiz-adv-x="709" d="M59 528l21 78q126 0 191 49t89 158l89 393q30 135 106 195.5t215 60.5h29l-17 -86q-86 -2 -129 -20.5t-69.5 -61.5t-44.5 -120l-74 -338q-30 -134 -91.5 -194.5t-164.5 -78.5v-4q68 -18 105.5 -68.5t37.5 -121.5q0 -52 -24 -164l-47 -225q-13 -58 -13 -101 q0 -61 37.5 -89t138.5 -28v-86h-20q-256 0 -256 199q0 45 16 115l56 252q18 90 18 127q0 159 -199 159z" /> +<glyph unicode="|" d="M584 -510v2071h100v-2071h-100z" /> +<glyph unicode="}" horiz-adv-x="709" d="M-41 -238q96 2 138 21t68.5 61t43.5 121l74 338q27 126 87.5 189.5t168.5 82.5v5q-75 20 -109.5 72.5t-34.5 117.5q0 55 18 131l54 258q12 61 12 101q0 44 -18 69t-54 36t-116 11l20 86h21q131 0 189.5 -51t58.5 -147q0 -41 -17 -115l-55 -252q-19 -95 -19 -127 q0 -77 49.5 -118.5t149.5 -41.5l-20 -78q-125 0 -191 -48.5t-90 -157.5l-88 -394q-32 -139 -108.5 -197.5t-213.5 -58.5h-18v86z" /> +<glyph unicode="~" d="M127 625v94q108 110 233 110q61 0 115 -13.5t156 -57.5q126 -58 219 -58q54 0 107.5 29t117.5 96v-96q-111 -113 -233 -113q-117 0 -271 72q-62 29 -112.5 43t-108.5 14q-49 0 -108 -30.5t-115 -89.5z" /> +<glyph unicode="&#xa1;" horiz-adv-x="502" d="M4 -375l260 1086h62l-203 -1086h-119zM272 981q0 55 25 89t68 34q67 0 67 -74q0 -56 -25 -88.5t-69 -32.5q-66 0 -66 72z" /> +<glyph unicode="&#xa2;" d="M250 600q0 184 63.5 341t178 253t256.5 111l36 178h90l-38 -176q116 -4 217 -43l-29 -90q-107 47 -217 47q-130 0 -233 -76t-162.5 -221t-59.5 -322q0 -164 74.5 -247t208.5 -83q127 0 264 60v-92q-118 -58 -281 -58l-40 -202h-93l45 215q-132 25 -206 132.5t-74 272.5z " /> +<glyph unicode="&#xa3;" d="M-4 0l16 84q93 11 165.5 95.5t107.5 236.5l57 260h-199l17 82h198l76 350q41 187 155 279t290 92q170 0 313 -78l-39 -84l-54 26q-108 50 -231 50q-134 0 -220.5 -74.5t-117.5 -220.5l-73 -340h409l-18 -82h-408l-57 -268q-50 -225 -188 -314h759l-20 -94h-938z" /> +<glyph unicode="&#xa4;" d="M207 1077l63 64l127 -129q105 78 230 78q118 0 223 -78l131 129l61 -62l-129 -129q78 -106 78 -227q0 -135 -78 -227l129 -127l-61 -62l-131 127q-104 -76 -223 -76q-126 0 -228 80l-129 -129l-61 62l127 127q-74 98 -74 225q0 118 74 225zM350 723q0 -116 80 -196.5 t197 -80.5t198.5 81t81.5 196q0 75 -36.5 140t-102.5 104t-141 39q-114 0 -195.5 -82t-81.5 -201z" /> +<glyph unicode="&#xa5;" d="M166 289l18 84h299l41 190h-301l17 76h258l-215 823h100l201 -817l544 817h117l-559 -823h266l-16 -76h-315l-39 -190h317l-18 -84h-316l-59 -289h-105l64 289h-299z" /> +<glyph unicode="&#xa6;" d="M578 246h100v-756h-100v756zM578 805v756h100v-756h-100z" /> +<glyph unicode="&#xa7;" horiz-adv-x="995" d="M102 51v99q47 -27 126 -46.5t153 -19.5q149 0 228 52.5t79 150.5q0 62 -42.5 106t-166.5 96q-155 65 -211.5 130t-56.5 159q0 101 69.5 182t198.5 130q-64 31 -103.5 85.5t-39.5 120.5q0 74 46 134.5t132.5 94.5t202.5 34q163 0 289 -58l-31 -80q-138 54 -264 54 q-124 0 -202.5 -46.5t-78.5 -123.5q0 -59 46 -104.5t183 -106.5q112 -52 158.5 -89.5t71 -85t24.5 -110.5q0 -197 -249 -317q122 -64 122 -197q0 -86 -48 -153.5t-139.5 -105.5t-221.5 -38q-157 0 -275 53zM303 786q0 -57 24.5 -96.5t81 -73t187.5 -81.5q103 49 162 113.5 t59 156.5q0 72 -57.5 126t-200.5 107q-119 -30 -187.5 -97.5t-68.5 -154.5z" /> +<glyph unicode="&#xa8;" horiz-adv-x="1135" d="M492 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM836 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="&#xa9;" horiz-adv-x="1704" d="M147 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM240 731q0 -178 88.5 -329.5t240.5 -240.5t330 -89q174 0 325 85.5t243 239t92 334.5q0 178 -89 330 t-240.5 241t-330.5 89q-182 0 -335 -92t-238.5 -243t-85.5 -325zM537 725q0 207 110 332t297 125q119 0 227 -52l-36 -83q-99 45 -191 45q-142 0 -222.5 -94.5t-80.5 -264.5q0 -186 74.5 -275t220.5 -89q85 0 199 43v-88q-104 -45 -209 -45q-187 0 -288 116t-101 330z" /> +<glyph unicode="&#xaa;" horiz-adv-x="643" d="M170 1032q0 189 90.5 321t226.5 132q55 0 97.5 -29t66.5 -86h6l35 103h66l-137 -650h-72l22 125h-4q-96 -137 -223 -137q-80 0 -127 56.5t-47 164.5zM258 1028q0 -143 111 -143q66 0 133.5 75.5t97.5 184.5q16 51 16 123q0 58 -36 100.5t-93 42.5q-94 0 -161.5 -111.5 t-67.5 -271.5z" /> +<glyph unicode="&#xab;" horiz-adv-x="860" d="M61 541l2 26l363 365l57 -49l-317 -336l213 -385l-64 -39zM422 541l2 26l362 365l58 -49l-314 -336l209 -385l-63 -39z" /> +<glyph unicode="&#xac;" d="M125 672v100h903v-500h-100v400h-803z" /> +<glyph unicode="&#xad;" horiz-adv-x="629" d="M77 502l18 90h457l-16 -90h-459z" /> +<glyph unicode="&#xae;" horiz-adv-x="1704" d="M150 731q0 207 103.5 382t276.5 272.5t371 97.5q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-204 0 -376.5 100.5t-273.5 273t-101 377.5zM242 731q0 -178 88.5 -329.5t240.5 -240.5t330 -89q174 0 325 85.5t243 239t92 334.5q0 178 -89 330 t-240.5 241t-330.5 89q-182 0 -335 -92t-238.5 -243t-85.5 -325zM657 291v880h211q143 0 222 -62t79 -191q0 -80 -39.5 -141t-109.5 -93l237 -393h-120l-211 360h-168v-360h-101zM758 731h112q93 0 144 46.5t51 135.5q0 172 -197 172h-110v-354z" /> +<glyph unicode="&#xaf;" horiz-adv-x="655" d="M348 1556l53 97h654l-54 -97h-653z" /> +<glyph unicode="&#xb0;" horiz-adv-x="877" d="M242 1190q0 120 85 206.5t208 86.5q122 0 207 -86.5t85 -206.5q0 -122 -85.5 -207.5t-206.5 -85.5q-122 0 -207.5 85.5t-85.5 207.5zM315 1190q0 -89 64.5 -153t155.5 -64q92 0 155.5 64t63.5 153q0 90 -64 155.5t-155 65.5q-90 0 -155 -65.5t-65 -155.5z" /> +<glyph unicode="&#xb1;" d="M127 0v100h903v-100h-903zM127 629v98h401v406h101v-406h401v-98h-401v-400h-101v400h-401z" /> +<glyph unicode="&#xb2;" horiz-adv-x="643" d="M82 586l16 80l297 258q137 118 182.5 190.5t45.5 153.5q0 59 -38.5 97t-105.5 38q-95 0 -194 -76l-41 62q108 90 239 90q73 0 125 -27t78.5 -72t26.5 -100q0 -106 -59 -198.5t-183 -194.5l-266 -223h416l-17 -78h-522z" /> +<glyph unicode="&#xb3;" horiz-adv-x="643" d="M109 625v90q46 -28 108 -48t125 -20q99 0 159 52.5t60 142.5q0 162 -196 162h-84l16 79h86q102 0 168.5 49.5t66.5 129.5q0 68 -37.5 102.5t-105.5 34.5q-100 0 -199 -68l-40 64q109 86 251 86q100 0 159 -56.5t59 -148.5q0 -85 -48.5 -148t-154.5 -88v-4 q66 -16 105.5 -68t39.5 -124q0 -77 -39 -141t-109 -99t-161 -35q-59 0 -123.5 15.5t-105.5 40.5z" /> +<glyph unicode="&#xb4;" horiz-adv-x="1135" d="M580 1241v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="&#xb5;" horiz-adv-x="1171" d="M-29 -492l338 1579h101l-152 -698q-20 -96 -20 -147q0 -82 48.5 -127t135.5 -45q110 0 207 64.5t162.5 182.5t101.5 285l104 485h99l-234 -1087h-78l29 205h-6q-164 -221 -404 -221q-85 0 -139 32.5t-76 89.5h-6q-18 -132 -51 -284l-63 -314h-97z" /> +<glyph unicode="&#xb6;" horiz-adv-x="1341" d="M215 1042q0 260 109 387t342 127h542v-1816h-100v1722h-227v-1722h-101v819q-64 -18 -145 -18q-216 0 -318 125t-102 376z" /> +<glyph unicode="&#xb7;" horiz-adv-x="485" d="M207 698q0 56 25 88.5t69 32.5q66 0 66 -72q0 -53 -25 -87.5t-67 -34.5q-68 0 -68 73z" /> +<glyph unicode="&#xb8;" horiz-adv-x="420" d="M-174 -406q30 -6 72 -6q198 0 198 115q0 97 -151 107l110 190h80l-78 -137q140 -30 140 -152q0 -94 -75.5 -148.5t-217.5 -54.5q-46 0 -78 7v79z" /> +<glyph unicode="&#xb9;" horiz-adv-x="643" d="M254 1288l258 174h80l-186 -876h-84l118 569q5 21 11.5 50.5t14 60t15.5 59t15 49.5q-34 -31 -60 -51.5t-143 -93.5z" /> +<glyph unicode="&#xba;" horiz-adv-x="655" d="M190 1059q0 112 41.5 209.5t116 154t170.5 56.5q105 0 165 -64t60 -180q0 -115 -40 -214t-114 -156.5t-175 -57.5q-114 0 -169 67.5t-55 184.5zM270 1067q0 -186 156 -186q73 0 125.5 46.5t81.5 127.5t29 176q0 83 -39 128.5t-115 45.5q-70 0 -124 -46.5t-84 -124.5 t-30 -167z" /> +<glyph unicode="&#xbb;" horiz-adv-x="860" d="M33 172l313 336l-209 385l64 39l254 -418l-2 -27l-363 -364zM393 172l314 336l-209 385l63 39l254 -418l-2 -27l-362 -364z" /> +<glyph unicode="&#xbc;" horiz-adv-x="1481" d="M715 230l21 76l506 577h86l-125 -581h133l-17 -72h-131l-49 -229h-82l49 229h-391zM830 302h291q61 294 79 365.5t29 105.5q-10 -16 -61 -79t-338 -392zM129 0l1086 1462h108l-1087 -1462h-107zM251 1288l258 174h80l-186 -876h-84l118 569q5 21 11.5 50.5t14 60t15.5 59 t15 49.5q-34 -31 -60 -51.5t-143 -93.5z" /> +<glyph unicode="&#xbd;" horiz-adv-x="1458" d="M756 1l16 80l297 258q137 118 182.5 190.5t45.5 153.5q0 59 -38.5 97t-105.5 38q-95 0 -194 -76l-41 62q108 90 239 90q73 0 125 -27t78.5 -72t26.5 -100q0 -106 -59 -198.5t-183 -194.5l-266 -223h416l-17 -78h-522zM173 1288l258 174h80l-186 -876h-84l118 569 q5 21 11.5 50.5t14 60t15.5 59t15 49.5q-34 -31 -60 -51.5t-143 -93.5zM53 0l1086 1462h108l-1087 -1462h-107z" /> +<glyph unicode="&#xbe;" horiz-adv-x="1458" d="M776 230l21 76l506 577h86l-125 -581h133l-17 -72h-131l-49 -229h-82l49 229h-391zM891 302h291q61 294 79 365.5t29 105.5q-10 -16 -61 -79t-338 -392zM71 625v90q46 -28 108 -48t125 -20q99 0 159 52.5t60 142.5q0 162 -196 162h-84l16 79h86q102 0 168.5 49.5 t66.5 129.5q0 68 -37.5 102.5t-105.5 34.5q-100 0 -199 -68l-40 64q109 86 251 86q100 0 159 -56.5t59 -148.5q0 -85 -48.5 -148t-154.5 -88v-4q66 -16 105.5 -68t39.5 -124q0 -77 -39 -141t-109 -99t-161 -35q-59 0 -123.5 15.5t-105.5 40.5zM213 0l1086 1462h108 l-1087 -1462h-107z" /> +<glyph unicode="&#xbf;" horiz-adv-x="799" d="M0 -90q0 133 70 240.5t227 220.5q85 61 133.5 109t73 95t45.5 142h92l-6 -29q-28 -127 -79 -200t-161 -154q-118 -84 -175 -145.5t-86.5 -127.5t-29.5 -141q0 -106 65.5 -168.5t184.5 -62.5q141 0 308 100l38 -86q-85 -49 -170.5 -77.5t-187.5 -28.5q-159 0 -250.5 84.5 t-91.5 228.5zM553 971q0 56 25 89.5t67 33.5q68 0 68 -74q0 -56 -25.5 -88.5t-69.5 -32.5q-65 0 -65 72z" /> +<glyph unicode="&#xc0;" horiz-adv-x="1059" d="M-111 0l822 1468h67l201 -1468h-105l-69 520h-512l-287 -520h-117zM344 612h449l-39 291q-31 242 -39 402q-30 -63 -64.5 -130t-306.5 -563zM536 1886v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="&#xc1;" horiz-adv-x="1059" d="M-111 0l822 1468h67l201 -1468h-105l-69 520h-512l-287 -520h-117zM344 612h449l-39 291q-31 242 -39 402q-30 -63 -64.5 -130t-306.5 -563zM668 1579v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="&#xc2;" horiz-adv-x="1059" d="M-111 0l822 1468h67l201 -1468h-105l-69 520h-512l-287 -520h-117zM344 612h449l-39 291q-31 242 -39 402q-30 -63 -64.5 -130t-306.5 -563zM493 1579v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5 t-125 -92.5h-54z" /> +<glyph unicode="&#xc3;" horiz-adv-x="1059" d="M-111 0l822 1468h67l201 -1468h-105l-69 520h-512l-287 -520h-117zM344 612h449l-39 291q-31 242 -39 402q-30 -63 -64.5 -130t-306.5 -563zM426 1581q19 108 71 166.5t134 58.5q41 0 73.5 -14t117.5 -72q52 -36 94 -36q43 0 71.5 30.5t46.5 100.5h76 q-26 -118 -74.5 -173t-124.5 -55q-40 0 -77.5 19t-75.5 45q-34 23 -64.5 41t-68.5 18q-45 0 -74 -28.5t-51 -100.5h-74z" /> +<glyph unicode="&#xc4;" horiz-adv-x="1059" d="M-111 0l822 1468h67l201 -1468h-105l-69 520h-512l-287 -520h-117zM344 612h449l-39 291q-31 242 -39 402q-30 -63 -64.5 -130t-306.5 -563zM535 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM879 1704q0 49 20.5 78t56.5 29q54 0 54 -64 q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="&#xc5;" horiz-adv-x="1059" d="M-111 0l822 1468h67l201 -1468h-105l-69 520h-512l-287 -520h-117zM344 612h449l-39 291q-31 242 -39 402q-30 -63 -64.5 -130t-306.5 -563zM539 1592q0 88 59.5 144t149.5 56q88 0 142.5 -50t54.5 -142t-57.5 -148.5t-145.5 -56.5q-93 0 -148 52t-55 145zM619 1592 q0 -57 33 -90t90 -33q56 0 90.5 36t34.5 93t-33.5 90t-87.5 33q-60 0 -93.5 -36t-33.5 -93z" /> +<glyph unicode="&#xc6;" horiz-adv-x="1640" d="M-117 0l946 1462h883l-20 -94h-625l-117 -553h590l-20 -94h-588l-135 -627h626l-20 -94h-727l110 522h-444l-328 -522h-131zM408 627h401l156 741h-88z" /> +<glyph unicode="&#xc7;" horiz-adv-x="1169" d="M170 535q0 266 104.5 488t284.5 341t402 119q177 0 307 -68l-45 -90q-55 30 -124.5 47t-137.5 17q-197 0 -351.5 -104.5t-245 -304.5t-90.5 -441q0 -225 110.5 -346t317.5 -121q140 0 304 51v-94q-156 -49 -316 -49q-252 0 -386 145t-134 410zM381 -406q30 -6 72 -6 q198 0 198 115q0 97 -151 107l110 190h80l-78 -137q140 -30 140 -152q0 -94 -75.5 -148.5t-217.5 -54.5q-46 0 -78 7v79z" /> +<glyph unicode="&#xc8;" horiz-adv-x="1067" d="M102 0l310 1462h727l-21 -94h-624l-117 -553h590l-21 -94h-588l-135 -627h627l-21 -94h-727zM612 1886v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="&#xc9;" horiz-adv-x="1067" d="M102 0l310 1462h727l-21 -94h-624l-117 -553h590l-21 -94h-588l-135 -627h627l-21 -94h-727zM654 1579v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="&#xca;" horiz-adv-x="1067" d="M102 0l310 1462h727l-21 -94h-624l-117 -553h590l-21 -94h-588l-135 -627h627l-21 -94h-727zM522 1579v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="&#xcb;" horiz-adv-x="1067" d="M102 0l310 1462h727l-21 -94h-624l-117 -553h590l-21 -94h-588l-135 -627h627l-21 -94h-727zM558 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM902 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="&#xcc;" horiz-adv-x="504" d="M102 0l310 1462h98l-309 -1462h-99zM246 1886v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="&#xcd;" horiz-adv-x="504" d="M102 0l310 1462h98l-309 -1462h-99zM419 1579v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="&#xce;" horiz-adv-x="504" d="M102 0l310 1462h98l-309 -1462h-99zM224 1579v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="&#xcf;" horiz-adv-x="504" d="M102 0l310 1462h98l-309 -1462h-99zM260 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM604 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="&#xd0;" horiz-adv-x="1352" d="M90 676l21 96h155l146 690h305q282 0 426.5 -147.5t144.5 -435.5q0 -253 -109.5 -461.5t-300.5 -313t-446 -104.5h-330l144 676h-156zM221 90h209q226 0 394.5 94.5t261 275.5t92.5 412q0 498 -476 498h-206l-129 -598h378l-20 -96h-379z" /> +<glyph unicode="&#xd1;" horiz-adv-x="1372" d="M102 0l310 1462h80l522 -1294h8q23 176 74 416l188 878h94l-309 -1462h-86l-516 1284h-8q-23 -149 -48 -273t-214 -1011h-95zM577 1581q19 108 71 166.5t134 58.5q41 0 73.5 -14t117.5 -72q52 -36 94 -36q43 0 71.5 30.5t46.5 100.5h76q-26 -118 -74.5 -173t-124.5 -55 q-40 0 -77.5 19t-75.5 45q-34 23 -64.5 41t-68.5 18q-45 0 -74 -28.5t-51 -100.5h-74z" /> +<glyph unicode="&#xd2;" horiz-adv-x="1464" d="M172 559q0 262 93 477.5t255 331t373 115.5q247 0 378.5 -148.5t131.5 -423.5q0 -255 -94 -481.5t-252 -338t-365 -111.5q-250 0 -385 149t-135 430zM276 573q0 -245 109.5 -373t319.5 -128q169 0 300 98.5t210 300t79 430.5q0 240 -104.5 364t-310.5 124 q-174 0 -308.5 -101t-214.5 -298t-80 -417zM710 1886v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="&#xd3;" horiz-adv-x="1464" d="M172 559q0 262 93 477.5t255 331t373 115.5q247 0 378.5 -148.5t131.5 -423.5q0 -255 -94 -481.5t-252 -338t-365 -111.5q-250 0 -385 149t-135 430zM276 573q0 -245 109.5 -373t319.5 -128q169 0 300 98.5t210 300t79 430.5q0 240 -104.5 364t-310.5 124 q-174 0 -308.5 -101t-214.5 -298t-80 -417zM844 1579v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="&#xd4;" horiz-adv-x="1464" d="M172 559q0 262 93 477.5t255 331t373 115.5q247 0 378.5 -148.5t131.5 -423.5q0 -255 -94 -481.5t-252 -338t-365 -111.5q-250 0 -385 149t-135 430zM276 573q0 -245 109.5 -373t319.5 -128q169 0 300 98.5t210 300t79 430.5q0 240 -104.5 364t-310.5 124 q-174 0 -308.5 -101t-214.5 -298t-80 -417zM657 1579v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="&#xd5;" horiz-adv-x="1464" d="M172 559q0 262 93 477.5t255 331t373 115.5q247 0 378.5 -148.5t131.5 -423.5q0 -255 -94 -481.5t-252 -338t-365 -111.5q-250 0 -385 149t-135 430zM276 573q0 -245 109.5 -373t319.5 -128q169 0 300 98.5t210 300t79 430.5q0 240 -104.5 364t-310.5 124 q-174 0 -308.5 -101t-214.5 -298t-80 -417zM592 1581q19 108 71 166.5t134 58.5q41 0 73.5 -14t117.5 -72q52 -36 94 -36q43 0 71.5 30.5t46.5 100.5h76q-26 -118 -74.5 -173t-124.5 -55q-40 0 -77.5 19t-75.5 45q-34 23 -64.5 41t-68.5 18q-45 0 -74 -28.5t-51 -100.5h-74z " /> +<glyph unicode="&#xd6;" horiz-adv-x="1464" d="M172 559q0 262 93 477.5t255 331t373 115.5q247 0 378.5 -148.5t131.5 -423.5q0 -255 -94 -481.5t-252 -338t-365 -111.5q-250 0 -385 149t-135 430zM276 573q0 -245 109.5 -373t319.5 -128q169 0 300 98.5t210 300t79 430.5q0 240 -104.5 364t-310.5 124 q-174 0 -308.5 -101t-214.5 -298t-80 -417zM687 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM1031 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="&#xd7;" d="M221 1055l70 69l330 -329l333 329l68 -67l-332 -334l332 -332l-68 -67l-333 329l-330 -327l-68 67l328 330z" /> +<glyph unicode="&#xd8;" horiz-adv-x="1464" d="M139 -14l146 172q-113 149 -113 401q0 263 94 479.5t256.5 330.5t370.5 114q219 0 352 -121l133 168l70 -53l-145 -183q45 -51 72.5 -161t27.5 -222q0 -187 -52 -365.5t-144.5 -304.5t-223 -193.5t-291.5 -67.5q-215 0 -348 112l-139 -170zM276 573q0 -105 21.5 -191 t56.5 -138l826 1032q-107 113 -301 113q-134 0 -244 -59.5t-188.5 -170t-124.5 -267.5t-46 -319zM412 172q107 -100 293 -100q170 0 301 100t209.5 296.5t78.5 432.5q0 85 -17.5 172t-43.5 129z" /> +<glyph unicode="&#xd9;" horiz-adv-x="1370" d="M176 381q0 83 27 201l186 880h103l-193 -899q-20 -89 -20 -184q0 -309 342 -309q195 0 307.5 96.5t158.5 318.5l207 977h101l-207 -977q-58 -270 -197 -387.5t-375 -117.5q-440 0 -440 401zM667 1886v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="&#xda;" horiz-adv-x="1370" d="M176 381q0 83 27 201l186 880h103l-193 -899q-20 -89 -20 -184q0 -309 342 -309q195 0 307.5 96.5t158.5 318.5l207 977h101l-207 -977q-58 -270 -197 -387.5t-375 -117.5q-440 0 -440 401zM838 1579v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5 t-192.5 -146.5h-67z" /> +<glyph unicode="&#xdb;" horiz-adv-x="1370" d="M176 381q0 83 27 201l186 880h103l-193 -899q-20 -89 -20 -184q0 -309 342 -309q195 0 307.5 96.5t158.5 318.5l207 977h101l-207 -977q-58 -270 -197 -387.5t-375 -117.5q-440 0 -440 401zM634 1579v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5 t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="&#xdc;" horiz-adv-x="1370" d="M176 381q0 83 27 201l186 880h103l-193 -899q-20 -89 -20 -184q0 -309 342 -309q195 0 307.5 96.5t158.5 318.5l207 977h101l-207 -977q-58 -270 -197 -387.5t-375 -117.5q-440 0 -440 401zM678 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29 q-55 0 -55 63zM1022 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="&#xdd;" horiz-adv-x="965" d="M193 1462h100l201 -817l544 817h117l-631 -932l-108 -530h-105l119 545zM563 1579v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="&#xde;" horiz-adv-x="1145" d="M102 0l310 1462h102l-57 -266h213q200 0 308.5 -92.5t108.5 -267.5q0 -247 -153 -373.5t-457 -126.5h-201l-71 -336h-103zM293 428h190q256 0 376 98.5t120 302.5q0 275 -330 275h-211z" /> +<glyph unicode="&#xdf;" horiz-adv-x="1094" d="M-281 -379q53 -24 115 -24q79 0 123 50.5t66 153.5l305 1409q80 357 405 357q137 0 215 -61.5t78 -174.5q0 -75 -44.5 -140.5t-166.5 -148.5q-107 -76 -141.5 -124.5t-34.5 -106.5q0 -51 34 -88.5t93 -75.5q96 -63 138 -133.5t42 -165.5q0 -170 -106.5 -269t-286.5 -99 q-143 0 -234 65v109q45 -36 112.5 -59t129.5 -23q132 0 208.5 71t76.5 195q0 75 -31.5 129t-109.5 108q-82 58 -119 110.5t-37 121.5q0 57 21 103t60.5 88.5t137.5 113.5q101 70 131.5 116t30.5 101q0 70 -55 110t-150 40q-129 0 -205 -76t-108 -229l-291 -1377 q-33 -152 -103.5 -220.5t-179.5 -68.5q-73 0 -119 23v90z" /> +<glyph unicode="&#xe0;" horiz-adv-x="1133" d="M102 354q0 197 75 376t200.5 276.5t277.5 97.5q232 0 279 -219h6l59 202h80l-229 -1087h-82l45 274h-6q-84 -142 -187 -218t-237 -76q-281 0 -281 374zM205 365q0 -152 50 -223.5t151 -71.5q89 0 177.5 62t159 166t107.5 230t37 213q0 79 -26 141.5t-77 99t-127 36.5 q-124 0 -224 -82t-164 -245.5t-64 -325.5zM530 1548v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="&#xe1;" horiz-adv-x="1133" d="M102 354q0 197 75 376t200.5 276.5t277.5 97.5q232 0 279 -219h6l59 202h80l-229 -1087h-82l45 274h-6q-84 -142 -187 -218t-237 -76q-281 0 -281 374zM205 365q0 -152 50 -223.5t151 -71.5q89 0 177.5 62t159 166t107.5 230t37 213q0 79 -26 141.5t-77 99t-127 36.5 q-124 0 -224 -82t-164 -245.5t-64 -325.5zM586 1241v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="&#xe2;" horiz-adv-x="1133" d="M102 354q0 197 75 376t200.5 276.5t277.5 97.5q232 0 279 -219h6l59 202h80l-229 -1087h-82l45 274h-6q-84 -142 -187 -218t-237 -76q-281 0 -281 374zM205 365q0 -152 50 -223.5t151 -71.5q89 0 177.5 62t159 166t107.5 230t37 213q0 79 -26 141.5t-77 99t-127 36.5 q-124 0 -224 -82t-164 -245.5t-64 -325.5zM441 1243v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="&#xe3;" horiz-adv-x="1133" d="M102 354q0 197 75 376t200.5 276.5t277.5 97.5q232 0 279 -219h6l59 202h80l-229 -1087h-82l45 274h-6q-84 -142 -187 -218t-237 -76q-281 0 -281 374zM205 365q0 -152 50 -223.5t151 -71.5q89 0 177.5 62t159 166t107.5 230t37 213q0 79 -26 141.5t-77 99t-127 36.5 q-124 0 -224 -82t-164 -245.5t-64 -325.5zM373 1243q19 108 71 166.5t134 58.5q41 0 73.5 -14t117.5 -72q52 -36 94 -36q43 0 71.5 30.5t46.5 100.5h76q-26 -118 -74.5 -173t-124.5 -55q-40 0 -77.5 19t-75.5 45q-34 23 -64.5 41t-68.5 18q-45 0 -74 -28.5t-51 -100.5h-74z " /> +<glyph unicode="&#xe4;" horiz-adv-x="1133" d="M102 354q0 197 75 376t200.5 276.5t277.5 97.5q232 0 279 -219h6l59 202h80l-229 -1087h-82l45 274h-6q-84 -142 -187 -218t-237 -76q-281 0 -281 374zM205 365q0 -152 50 -223.5t151 -71.5q89 0 177.5 62t159 166t107.5 230t37 213q0 79 -26 141.5t-77 99t-127 36.5 q-124 0 -224 -82t-164 -245.5t-64 -325.5zM491 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM835 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="&#xe5;" horiz-adv-x="1133" d="M102 354q0 197 75 376t200.5 276.5t277.5 97.5q232 0 279 -219h6l59 202h80l-229 -1087h-82l45 274h-6q-84 -142 -187 -218t-237 -76q-281 0 -281 374zM205 365q0 -152 50 -223.5t151 -71.5q89 0 177.5 62t159 166t107.5 230t37 213q0 79 -26 141.5t-77 99t-127 36.5 q-124 0 -224 -82t-164 -245.5t-64 -325.5zM521 1440q0 88 59.5 144t149.5 56q88 0 142.5 -50t54.5 -142t-57.5 -148.5t-145.5 -56.5q-93 0 -148 52t-55 145zM601 1440q0 -57 33 -90t90 -33q56 0 90.5 36t34.5 93t-33.5 90t-87.5 33q-60 0 -93.5 -36t-33.5 -93z" /> +<glyph unicode="&#xe6;" horiz-adv-x="1602" d="M102 344q0 206 70.5 384.5t192.5 277t274 98.5q106 0 166 -56.5t74 -156.5h10l59 192h66l-35 -186q139 207 350 207q112 0 175 -61.5t63 -172.5q0 -179 -158.5 -271.5t-470.5 -92.5h-39q-8 -51 -8 -96q0 -161 69.5 -250.5t217.5 -89.5q69 0 133.5 21t130.5 52v-94 q-80 -37 -147 -53t-140 -16q-123 0 -211 60t-117 165l-39 -205h-77l41 254h-9q-94 -142 -189 -208t-208 -66q-120 0 -182 94t-62 270zM205 352q0 -150 42.5 -216t121.5 -66q67 0 138.5 42t134 117.5t106 170.5t63.5 199t20 165q0 118 -49 186t-141 68q-123 0 -223 -86 t-156.5 -240t-56.5 -340zM913 594h48q263 0 383 67t120 203q0 71 -38.5 112.5t-108.5 41.5q-119 0 -232 -115.5t-172 -308.5z" /> +<glyph unicode="&#xe7;" horiz-adv-x="887" d="M102 397q0 193 73.5 361.5t198.5 257t290 88.5q134 0 241 -43l-28 -90q-107 47 -218 47q-129 0 -232.5 -77t-162.5 -222t-59 -320q0 -158 73.5 -243.5t208.5 -85.5q71 0 131.5 13t131.5 46v-92q-116 -57 -273 -57q-174 0 -274.5 110.5t-100.5 306.5zM203 -406 q30 -6 72 -6q198 0 198 115q0 97 -151 107l110 190h80l-78 -137q140 -30 140 -152q0 -94 -75.5 -148.5t-217.5 -54.5q-46 0 -78 7v79z" /> +<glyph unicode="&#xe8;" horiz-adv-x="928" d="M102 395q0 181 71 347t195.5 264t274.5 98q114 0 182 -61t68 -166q0 -181 -163.5 -276t-485.5 -95h-33q-6 -44 -6 -98q0 -165 74 -251.5t213 -86.5q132 0 276 73v-94q-140 -69 -299 -69q-173 0 -270 109.5t-97 305.5zM225 594h49q517 0 517 270q0 67 -43.5 110.5 t-116.5 43.5q-131 0 -243.5 -115.5t-162.5 -308.5zM472 1548v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="&#xe9;" horiz-adv-x="928" d="M102 395q0 181 71 347t195.5 264t274.5 98q114 0 182 -61t68 -166q0 -181 -163.5 -276t-485.5 -95h-33q-6 -44 -6 -98q0 -165 74 -251.5t213 -86.5q132 0 276 73v-94q-140 -69 -299 -69q-173 0 -270 109.5t-97 305.5zM225 594h49q517 0 517 270q0 67 -43.5 110.5 t-116.5 43.5q-131 0 -243.5 -115.5t-162.5 -308.5zM532 1241v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="&#xea;" horiz-adv-x="928" d="M102 395q0 181 71 347t195.5 264t274.5 98q114 0 182 -61t68 -166q0 -181 -163.5 -276t-485.5 -95h-33q-6 -44 -6 -98q0 -165 74 -251.5t213 -86.5q132 0 276 73v-94q-140 -69 -299 -69q-173 0 -270 109.5t-97 305.5zM225 594h49q517 0 517 270q0 67 -43.5 110.5 t-116.5 43.5q-131 0 -243.5 -115.5t-162.5 -308.5zM390 1241v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="&#xeb;" horiz-adv-x="928" d="M102 395q0 181 71 347t195.5 264t274.5 98q114 0 182 -61t68 -166q0 -181 -163.5 -276t-485.5 -95h-33q-6 -44 -6 -98q0 -165 74 -251.5t213 -86.5q132 0 276 73v-94q-140 -69 -299 -69q-173 0 -270 109.5t-97 305.5zM225 594h49q517 0 517 270q0 67 -43.5 110.5 t-116.5 43.5q-131 0 -243.5 -115.5t-162.5 -308.5zM436 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM780 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="&#xec;" horiz-adv-x="475" d="M76 0l231 1087h96l-229 -1087h-98zM175 1548v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="&#xed;" horiz-adv-x="475" d="M76 0l231 1087h96l-229 -1087h-98zM284 1241v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="&#xee;" horiz-adv-x="475" d="M76 0l231 1087h96l-229 -1087h-98zM128 1241v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="&#xef;" horiz-adv-x="475" d="M76 0l231 1087h96l-229 -1087h-98zM171 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM515 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="&#xf0;" horiz-adv-x="1124" d="M102 381q0 170 63 301.5t178.5 203.5t262.5 72q107 0 188 -49.5t121 -142.5h5q0 139 -43 289t-115 243l-295 -163l-39 73l285 156q-54 60 -158 139l59 68q32 -26 81 -66t100 -94l266 150l39 -74l-256 -141q87 -116 131.5 -276t44.5 -335q0 -355 -141.5 -555t-399.5 -200 q-177 0 -277 106.5t-100 294.5zM205 389q0 -153 73.5 -236t210.5 -83q118 0 208.5 61t144 186.5t53.5 270.5q0 77 -35 142t-100 101.5t-156 36.5q-124 0 -213.5 -61.5t-137.5 -169.5t-48 -248z" /> +<glyph unicode="&#xf1;" horiz-adv-x="1143" d="M76 0l231 1087h82l-37 -221h6q164 238 416 238q130 0 195 -64t65 -184q0 -70 -24 -182l-148 -674h-98l149 692q21 92 21 156q0 80 -43.5 125t-134.5 45q-112 0 -210.5 -67t-166 -187.5t-103.5 -286.5l-102 -477h-98zM389 1243q19 108 71 166.5t134 58.5q41 0 73.5 -14 t117.5 -72q52 -36 94 -36q43 0 71.5 30.5t46.5 100.5h76q-26 -118 -74.5 -173t-124.5 -55q-40 0 -77.5 19t-75.5 45q-34 23 -64.5 41t-68.5 18q-45 0 -74 -28.5t-51 -100.5h-74z" /> +<glyph unicode="&#xf2;" horiz-adv-x="1124" d="M98 403q0 191 73 358t197 257t281 90q180 0 278.5 -108.5t98.5 -299.5q0 -197 -71.5 -368.5t-195.5 -261.5t-286 -90q-184 0 -279.5 109.5t-95.5 313.5zM201 408q0 -342 282 -342q127 0 225.5 77.5t157 228t58.5 330.5q0 154 -73 237t-210 83q-124 0 -223 -78.5 t-158 -225t-59 -310.5zM465 1548v21h115q46 -129 164 -303v-25h-66q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="&#xf3;" horiz-adv-x="1124" d="M98 403q0 191 73 358t197 257t281 90q180 0 278.5 -108.5t98.5 -299.5q0 -197 -71.5 -368.5t-195.5 -261.5t-286 -90q-184 0 -279.5 109.5t-95.5 313.5zM201 408q0 -342 282 -342q127 0 225.5 77.5t157 228t58.5 330.5q0 154 -73 237t-210 83q-124 0 -223 -78.5 t-158 -225t-59 -310.5zM573 1241v21q66 51 150.5 142t129.5 165h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="&#xf4;" horiz-adv-x="1124" d="M98 403q0 191 73 358t197 257t281 90q180 0 278.5 -108.5t98.5 -299.5q0 -197 -71.5 -368.5t-195.5 -261.5t-286 -90q-184 0 -279.5 109.5t-95.5 313.5zM201 408q0 -342 282 -342q127 0 225.5 77.5t157 228t58.5 330.5q0 154 -73 237t-210 83q-124 0 -223 -78.5 t-158 -225t-59 -310.5zM427 1241v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="&#xf5;" horiz-adv-x="1124" d="M98 403q0 191 73 358t197 257t281 90q180 0 278.5 -108.5t98.5 -299.5q0 -197 -71.5 -368.5t-195.5 -261.5t-286 -90q-184 0 -279.5 109.5t-95.5 313.5zM201 408q0 -342 282 -342q127 0 225.5 77.5t157 228t58.5 330.5q0 154 -73 237t-210 83q-124 0 -223 -78.5 t-158 -225t-59 -310.5zM354 1243q19 108 71 166.5t134 58.5q41 0 73.5 -14t117.5 -72q52 -36 94 -36q43 0 71.5 30.5t46.5 100.5h76q-26 -118 -74.5 -173t-124.5 -55q-40 0 -77.5 19t-75.5 45q-34 23 -64.5 41t-68.5 18q-45 0 -74 -28.5t-51 -100.5h-74z" /> +<glyph unicode="&#xf6;" horiz-adv-x="1124" d="M98 403q0 191 73 358t197 257t281 90q180 0 278.5 -108.5t98.5 -299.5q0 -197 -71.5 -368.5t-195.5 -261.5t-286 -90q-184 0 -279.5 109.5t-95.5 313.5zM201 408q0 -342 282 -342q127 0 225.5 77.5t157 228t58.5 330.5q0 154 -73 237t-210 83q-124 0 -223 -78.5 t-158 -225t-59 -310.5zM468 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM812 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="&#xf7;" d="M168 672v100h903v-100h-903zM522 373q0 106 96 106q48 0 73.5 -27.5t25.5 -78.5q0 -57 -29 -82t-70 -25q-96 0 -96 107zM522 1071q0 107 96 107q46 0 72.5 -27.5t26.5 -79.5q0 -57 -29 -81.5t-70 -24.5q-96 0 -96 106z" /> +<glyph unicode="&#xf8;" horiz-adv-x="1124" d="M45 -18l119 145q-66 106 -66 276q0 191 73 358t197 257t281 90q150 0 250 -82l109 133l65 -53l-117 -143q70 -105 70 -263q0 -197 -71.5 -368.5t-195.5 -261.5t-286 -90q-163 0 -254 83l-110 -135zM201 408q0 -125 32 -197l605 739q-74 72 -197 72q-124 0 -223 -78.5 t-158 -225t-59 -310.5zM281 139q67 -73 202 -73q127 0 225.5 77.5t157 228t58.5 330.5q0 101 -35 179z" /> +<glyph unicode="&#xf9;" horiz-adv-x="1143" d="M109 227q0 60 22 170l150 690h100l-152 -698q-22 -106 -22 -158q0 -74 47.5 -117.5t138.5 -43.5q110 0 207.5 65.5t164 187t99.5 279.5l105 485h98l-231 -1087h-80l28 205h-6q-167 -221 -403 -221q-131 0 -198.5 62t-67.5 181zM495 1548v21h115q46 -129 164 -303v-25h-66 q-50 52 -114 144.5t-99 162.5z" /> +<glyph unicode="&#xfa;" horiz-adv-x="1143" d="M109 227q0 60 22 170l150 690h100l-152 -698q-22 -106 -22 -158q0 -74 47.5 -117.5t138.5 -43.5q110 0 207.5 65.5t164 187t99.5 279.5l105 485h98l-231 -1087h-80l28 205h-6q-167 -221 -403 -221q-131 0 -198.5 62t-67.5 181zM627 1241v21q66 51 150.5 142t129.5 165 h137v-23q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="&#xfb;" horiz-adv-x="1143" d="M109 227q0 60 22 170l150 690h100l-152 -698q-22 -106 -22 -158q0 -74 47.5 -117.5t138.5 -43.5q110 0 207.5 65.5t164 187t99.5 279.5l105 485h98l-231 -1087h-80l28 205h-6q-167 -221 -403 -221q-131 0 -198.5 62t-67.5 181zM443 1241v29q68 56 157.5 148.5 t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="&#xfc;" horiz-adv-x="1143" d="M109 227q0 60 22 170l150 690h100l-152 -698q-22 -106 -22 -158q0 -74 47.5 -117.5t138.5 -43.5q110 0 207.5 65.5t164 187t99.5 279.5l105 485h98l-231 -1087h-80l28 205h-6q-167 -221 -403 -221q-131 0 -198.5 62t-67.5 181zM483 1366q0 49 20.5 78t56.5 29 q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM827 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="&#xfd;" horiz-adv-x="920" d="M-217 -379q71 -27 137 -27q80 0 147 49.5t130 164.5t100 184l-174 1095h100l82 -548q51 -351 55 -449h11q43 105 186 367l348 630h103l-713 -1290q-72 -127 -122.5 -178t-114 -81t-146.5 -30q-68 0 -129 21v92zM505 1241v21q66 51 150.5 142t129.5 165h137v-23 q-51 -66 -157.5 -158.5t-192.5 -146.5h-67z" /> +<glyph unicode="&#xfe;" horiz-adv-x="1163" d="M-33 -492l434 2048h99q-114 -535 -164 -751h6q93 156 199 229.5t231 73.5q133 0 206 -92.5t73 -282.5q0 -195 -72 -371t-197.5 -277t-283.5 -101q-230 0 -279 219h-4q-13 -72 -149 -695h-99zM266 346q0 -125 61.5 -200.5t168.5 -75.5q124 0 225 84t164 243.5t63 325.5 q0 295 -200 295q-86 0 -172.5 -57.5t-162.5 -169.5t-111.5 -238t-35.5 -207z" /> +<glyph unicode="&#xff;" horiz-adv-x="920" d="M-217 -379q71 -27 137 -27q80 0 147 49.5t130 164.5t100 184l-174 1095h100l82 -548q51 -351 55 -449h11q43 105 186 367l348 630h103l-713 -1290q-72 -127 -122.5 -178t-114 -81t-146.5 -30q-68 0 -129 21v92zM354 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77 t-55 -29q-55 0 -55 63zM698 1366q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="&#x131;" horiz-adv-x="475" d="M76 0l231 1087h96l-229 -1087h-98z" /> +<glyph unicode="&#x152;" horiz-adv-x="1767" d="M172 559q0 263 96 482t262 330.5t381 111.5q130 0 240 -21h688l-20 -94h-625l-117 -553h590l-20 -94h-588l-135 -627h626l-20 -94h-666q-25 -6 -77.5 -13t-94.5 -7q-251 0 -385.5 149.5t-134.5 429.5zM276 573q0 -245 109 -373t320 -128q68 0 116 12l271 1290 q-110 15 -189 15q-182 0 -321.5 -98.5t-222.5 -293.5t-83 -424z" /> +<glyph unicode="&#x153;" horiz-adv-x="1720" d="M98 403q0 191 73 358t197 257t281 90q141 0 237 -74.5t126 -212.5q70 132 182.5 207.5t241.5 75.5q114 0 182 -61t68 -166q0 -181 -163.5 -276t-486.5 -95h-32q-7 -38 -7 -98q0 -165 74 -251.5t213 -86.5q133 0 277 73v-94q-140 -69 -299 -69q-135 0 -228 69t-125 201 q-65 -127 -179 -198.5t-257 -71.5q-184 0 -279.5 109.5t-95.5 313.5zM201 408q0 -342 282 -342q127 0 225.5 77.5t157 228t58.5 330.5q0 154 -73 237t-210 83q-124 0 -223 -78.5t-158 -225t-59 -310.5zM1018 594h49q516 0 516 270q0 70 -44.5 112t-115.5 42 q-131 0 -243 -115t-162 -309z" /> +<glyph unicode="&#x178;" horiz-adv-x="965" d="M193 1462h100l201 -817l544 817h117l-631 -932l-108 -530h-105l119 545zM454 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63zM798 1704q0 49 20.5 78t56.5 29q54 0 54 -64q0 -48 -21 -77t-55 -29q-55 0 -55 63z" /> +<glyph unicode="&#x2c6;" horiz-adv-x="1135" d="M444 1241v29q68 56 157.5 148.5t127.5 150.5h64q23 -64 72.5 -152.5t92.5 -146.5v-29h-49q-70 60 -161 207q-55 -57 -125 -114.5t-125 -92.5h-54z" /> +<glyph unicode="&#x2da;" horiz-adv-x="1182" d="M561 1440q0 88 59.5 144t149.5 56q88 0 142.5 -50t54.5 -142t-57.5 -148.5t-145.5 -56.5q-93 0 -148 52t-55 145zM641 1440q0 -57 33 -90t90 -33q56 0 90.5 36t34.5 93t-33.5 90t-87.5 33q-60 0 -93.5 -36t-33.5 -93z" /> +<glyph unicode="&#x2dc;" horiz-adv-x="1135" d="M346 1243q19 108 71 166.5t134 58.5q41 0 73.5 -14t117.5 -72q52 -36 94 -36q43 0 71.5 30.5t46.5 100.5h76q-26 -118 -74.5 -173t-124.5 -55q-40 0 -77.5 19t-75.5 45q-34 23 -64.5 41t-68.5 18q-45 0 -74 -28.5t-51 -100.5h-74z" /> +<glyph unicode="&#x2000;" horiz-adv-x="953" /> +<glyph unicode="&#x2001;" horiz-adv-x="1907" /> +<glyph unicode="&#x2002;" horiz-adv-x="953" /> +<glyph unicode="&#x2003;" horiz-adv-x="1907" /> +<glyph unicode="&#x2004;" horiz-adv-x="635" /> +<glyph unicode="&#x2005;" horiz-adv-x="476" /> +<glyph unicode="&#x2006;" horiz-adv-x="317" /> +<glyph unicode="&#x2007;" horiz-adv-x="317" /> +<glyph unicode="&#x2008;" horiz-adv-x="238" /> +<glyph unicode="&#x2009;" horiz-adv-x="381" /> +<glyph unicode="&#x200a;" horiz-adv-x="105" /> +<glyph unicode="&#x2010;" horiz-adv-x="629" d="M82 502l18 90h457l-16 -90h-459z" /> +<glyph unicode="&#x2011;" horiz-adv-x="629" d="M82 502l18 90h457l-16 -90h-459z" /> +<glyph unicode="&#x2012;" horiz-adv-x="629" d="M82 502l18 90h457l-16 -90h-459z" /> +<glyph unicode="&#x2013;" horiz-adv-x="983" d="M66 502l18 90h807l-17 -90h-808z" /> +<glyph unicode="&#x2014;" horiz-adv-x="1966" d="M68 502l18 90h1788l-16 -90h-1790z" /> +<glyph unicode="&#x2018;" horiz-adv-x="299" d="M129 983q41 100 116 231t161 248h73q-66 -106 -129.5 -242.5t-103.5 -258.5h-113z" /> +<glyph unicode="&#x2019;" horiz-adv-x="299" d="M129 961q66 106 129.5 242.5t103.5 258.5h113l4 -22q-43 -105 -117.5 -235.5t-158.5 -243.5h-74z" /> +<glyph unicode="&#x201a;" horiz-adv-x="451" d="M-100 -264q68 110 131.5 248t101.5 254h113l4 -23q-40 -97 -115.5 -230t-161.5 -249h-73z" /> +<glyph unicode="&#x201c;" horiz-adv-x="631" d="M129 983q41 100 116 231t161 248h73q-66 -106 -129.5 -242.5t-103.5 -258.5h-113zM463 983q43 104 120 238.5t156 240.5h74q-66 -106 -129.5 -242.5t-103.5 -258.5h-113z" /> +<glyph unicode="&#x201d;" horiz-adv-x="631" d="M129 961q66 106 129.5 242.5t103.5 258.5h113l4 -22q-43 -105 -117.5 -235.5t-158.5 -243.5h-74zM463 961q66 106 129.5 242.5t103.5 258.5h113l4 -22q-43 -105 -117.5 -235.5t-158.5 -243.5h-74z" /> +<glyph unicode="&#x201e;" horiz-adv-x="776" d="M-119 -264q73 119 135.5 254.5t98.5 247.5h112l4 -23q-43 -105 -117.5 -235.5t-158.5 -243.5h-74zM215 -264q66 108 129 242.5t105 259.5h112l4 -23q-43 -105 -117.5 -235.5t-158.5 -243.5h-74z" /> +<glyph unicode="&#x2022;" horiz-adv-x="793" d="M248 682q0 137 63 213t172 76q76 0 116 -39.5t40 -118.5q0 -125 -66 -207t-176 -82q-149 0 -149 158z" /> +<glyph unicode="&#x2026;" horiz-adv-x="1489" d="M69 55q0 56 25 88.5t69 32.5q66 0 66 -72q0 -53 -25 -87.5t-67 -34.5q-68 0 -68 73zM569 55q0 56 25 88.5t69 32.5q66 0 66 -72q0 -53 -25 -87.5t-67 -34.5q-68 0 -68 73zM1071 55q0 56 25 88.5t69 32.5q66 0 66 -72q0 -53 -25 -87.5t-67 -34.5q-68 0 -68 73z" /> +<glyph unicode="&#x202f;" horiz-adv-x="381" /> +<glyph unicode="&#x2039;" horiz-adv-x="537" d="M86 541l2 26l363 365l57 -49l-318 -336l213 -385l-63 -39z" /> +<glyph unicode="&#x203a;" horiz-adv-x="537" d="M37 172l317 336l-213 385l64 39l254 -418l-2 -27l-363 -364z" /> +<glyph unicode="&#x2044;" horiz-adv-x="274" d="M-463 0l1086 1462h108l-1087 -1462h-107z" /> +<glyph unicode="&#x205f;" horiz-adv-x="476" /> +<glyph unicode="&#x2074;" horiz-adv-x="643" d="M53 815l21 76l506 577h86l-125 -581h133l-17 -72h-131l-49 -229h-82l49 229h-391zM168 887h291q61 294 79 365.5t29 105.5q-10 -16 -61 -79t-338 -392z" /> +<glyph unicode="&#x20ac;" d="M80 541l16 82h172q5 101 35 217h-170l19 82h174q95 273 270 417t399 144q166 0 287 -90l-53 -82q-102 78 -238 78q-186 0 -330.5 -120.5t-226.5 -346.5h457l-21 -82h-460q-30 -98 -39 -217h442l-20 -82h-424q0 -243 89 -356t265 -113q115 0 252 57v-94q-129 -55 -270 -55 q-209 0 -325 139.5t-116 394.5v27h-184z" /> +<glyph unicode="&#x2122;" horiz-adv-x="1534" d="M174 1384v78h522v-78h-219v-643h-86v643h-217zM772 741v721h125l221 -606l223 606h125v-721h-86v398l4 207h-6l-227 -605h-74l-221 609h-6l4 -201v-408h-82z" /> +<glyph unicode="&#xe000;" horiz-adv-x="1085" d="M0 1085h1085v-1085h-1085v1085z" /> +<glyph unicode="&#xfb00;" horiz-adv-x="1155" d="M-233 -383q53 -16 100 -16q88 0 134 53t75 186l246 1166h-205l14 67l205 14l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-25 -80q-87 27 -147 27q-96 0 -153.5 -53.5t-84.5 -178.5l-35 -164h477l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-24 -80 q-87 27 -148 27q-97 0 -154.5 -54.5t-82.5 -177.5l-35 -164h248l-17 -81h-248l-252 -1190q-34 -165 -105.5 -236.5t-193.5 -71.5q-48 0 -102 19v90q53 -16 100 -16q88 0 134 53t75 186l244 1166h-477l-252 -1190q-33 -161 -104 -234.5t-195 -73.5q-48 0 -102 19v90z" /> +<glyph unicode="&#xfb01;" horiz-adv-x="1040" d="M641 0l231 1087h96l-229 -1087h-98zM915 1366q0 55 22 88t60 33q57 0 57 -72q0 -57 -22 -90t-57 -33q-29 0 -44.5 19.5t-15.5 54.5zM-250 -383q53 -16 100 -16q88 0 134 53t75 186l246 1166h-205l14 67l205 14l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-25 -80 q-87 27 -147 27q-96 0 -153.5 -53.5t-84.5 -178.5l-35 -164h248l-16 -81h-248l-252 -1190q-33 -161 -104 -234.5t-195 -73.5q-48 0 -102 19v90z" /> +<glyph unicode="&#xfb02;" horiz-adv-x="1042" d="M643 0l334 1556h94l-334 -1556h-94zM-250 -383q53 -16 100 -16q88 0 134 53t75 186l246 1166h-205l14 67l205 14l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-25 -80q-87 27 -147 27q-96 0 -153.5 -53.5t-84.5 -178.5l-35 -164h248l-16 -81h-248l-252 -1190 q-33 -161 -104 -234.5t-195 -73.5q-48 0 -102 19v90z" /> +<glyph unicode="&#xfb03;" horiz-adv-x="1616" d="M-250 -383q53 -16 100 -16q88 0 134 53t75 186l246 1166h-205l14 67l205 14l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-25 -80q-87 27 -147 27q-96 0 -153.5 -53.5t-84.5 -178.5l-35 -164h477l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-24 -80 q-87 27 -148 27q-97 0 -154.5 -54.5t-82.5 -177.5l-35 -164h248l-17 -81h-248l-252 -1190q-34 -165 -105.5 -236.5t-193.5 -71.5q-48 0 -102 19v90q53 -16 100 -16q88 0 134 53t75 186l244 1166h-477l-252 -1190q-33 -161 -104 -234.5t-195 -73.5q-48 0 -102 19v90zM1217 0 l231 1087h96l-229 -1087h-98zM1491 1366q0 55 22 88t60 33q57 0 57 -72q0 -57 -22 -90t-57 -33q-29 0 -44.5 19.5t-15.5 54.5z" /> +<glyph unicode="&#xfb04;" horiz-adv-x="1626" d="M-250 -383q53 -16 100 -16q88 0 134 53t75 186l246 1166h-205l14 67l205 14l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-25 -80q-87 27 -147 27q-96 0 -153.5 -53.5t-84.5 -178.5l-35 -164h477l35 160q35 168 116.5 244t227.5 76q73 0 166 -31l-24 -80 q-87 27 -148 27q-97 0 -154.5 -54.5t-82.5 -177.5l-35 -164h248l-17 -81h-248l-252 -1190q-34 -165 -105.5 -236.5t-193.5 -71.5q-48 0 -102 19v90q53 -16 100 -16q88 0 134 53t75 186l244 1166h-477l-252 -1190q-33 -161 -104 -234.5t-195 -73.5q-48 0 -102 19v90zM1227 0 l334 1556h94l-334 -1556h-94z" /> +</font> +</defs></svg> +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-LightItalic-webfont.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.svg b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.svg @@ -0,0 +1,252 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata> +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom +</metadata> +<defs> +<font id="OpenSansRegular" horiz-adv-x="1171" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="&#x09;" horiz-adv-x="532" /> +<glyph unicode="&#xa0;" horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="547" d="M152 106q0 136 120 136q58 0 89.5 -35t31.5 -101q0 -64 -32 -99.5t-89 -35.5q-52 0 -86 31.5t-34 103.5zM170 1462h207l-51 -1059h-105z" /> +<glyph unicode="&#x22;" horiz-adv-x="821" d="M133 1462h186l-40 -528h-105zM502 1462h186l-41 -528h-104z" /> +<glyph unicode="#" horiz-adv-x="1323" d="M51 430v129h287l68 340h-277v127h299l82 436h139l-82 -436h305l84 436h134l-84 -436h264v-127h-289l-66 -340h283v-129h-307l-84 -430h-137l84 430h-303l-82 -430h-136l80 430h-262zM475 559h303l66 340h-303z" /> +<glyph unicode="$" d="M131 170v156q83 -37 191.5 -60.5t197.5 -23.5v440q-205 65 -287.5 151t-82.5 222q0 131 101.5 215t268.5 102v182h129v-180q184 -5 355 -74l-52 -131q-149 59 -303 70v-434q157 -50 235 -97.5t115 -109t37 -149.5q0 -136 -102 -224.5t-285 -111.5v-232h-129v223 q-112 0 -217 17.5t-172 48.5zM319 1057q0 -76 45 -122t156 -87v387q-99 -16 -150 -62.5t-51 -115.5zM649 252q217 30 217 184q0 72 -44.5 116.5t-172.5 88.5v-389z" /> +<glyph unicode="%" horiz-adv-x="1686" d="M104 1026q0 227 74.5 342t220.5 115q145 0 223 -119t78 -338q0 -228 -76.5 -344.5t-224.5 -116.5q-140 0 -217.5 119t-77.5 342zM242 1026q0 -170 37 -255t120 -85q164 0 164 340q0 338 -164 338q-83 0 -120 -84t-37 -254zM365 0l811 1462h147l-811 -1462h-147zM985 440 q0 227 74.5 342t220.5 115q142 0 221.5 -117.5t79.5 -339.5q0 -227 -76.5 -343.5t-224.5 -116.5q-142 0 -218.5 119t-76.5 341zM1122 440q0 -171 37 -255.5t121 -84.5t124 83.5t40 256.5q0 171 -40 253.5t-124 82.5t-121 -82.5t-37 -253.5z" /> +<glyph unicode="&#x26;" horiz-adv-x="1495" d="M113 379q0 130 69.5 230t249.5 202q-85 95 -115.5 144t-48.5 102t-18 110q0 150 98 234t273 84q162 0 255 -83.5t93 -232.5q0 -107 -68 -197.5t-225 -183.5l407 -391q56 62 89.5 145.5t56.5 182.5h168q-68 -286 -205 -434l299 -291h-229l-185 178q-118 -106 -240 -152 t-272 -46q-215 0 -333.5 106t-118.5 293zM285 383q0 -117 77.5 -185.5t206.5 -68.5q241 0 400 154l-437 424q-111 -68 -157 -112.5t-68 -95.5t-22 -116zM414 1171q0 -69 36 -131.5t123 -150.5q129 75 179.5 138.5t50.5 146.5q0 77 -51.5 125.5t-137.5 48.5q-89 0 -144.5 -48 t-55.5 -129z" /> +<glyph unicode="'" horiz-adv-x="453" d="M133 1462h186l-40 -528h-105z" /> +<glyph unicode="(" horiz-adv-x="606" d="M82 561q0 265 77.5 496t223.5 405h162q-144 -193 -216.5 -424t-72.5 -475q0 -240 74 -469t213 -418h-160q-147 170 -224 397t-77 488z" /> +<glyph unicode=")" horiz-adv-x="606" d="M61 1462h162q147 -175 224 -406.5t77 -494.5t-77.5 -490t-223.5 -395h-160q139 188 213 417.5t74 469.5q0 244 -72.5 475t-216.5 424z" /> +<glyph unicode="*" horiz-adv-x="1130" d="M86 1090l29 182l391 -111l-43 395h194l-43 -395l398 111l26 -182l-381 -31l248 -326l-172 -94l-176 362l-160 -362l-176 94l242 326z" /> +<glyph unicode="+" d="M104 653v138h410v428h139v-428h412v-138h-412v-426h-139v426h-410z" /> +<glyph unicode="," horiz-adv-x="502" d="M63 -264q27 104 59.5 257t45.5 245h182l15 -23q-26 -100 -75 -232.5t-102 -246.5h-125z" /> +<glyph unicode="-" horiz-adv-x="659" d="M84 473v152h491v-152h-491z" /> +<glyph unicode="." horiz-adv-x="545" d="M152 106q0 67 30.5 101.5t87.5 34.5q58 0 90.5 -34.5t32.5 -101.5q0 -65 -33 -100t-90 -35q-51 0 -84.5 31.5t-33.5 103.5z" /> +<glyph unicode="/" horiz-adv-x="752" d="M20 0l545 1462h166l-545 -1462h-166z" /> +<glyph unicode="0" d="M102 733q0 382 119 567t363 185q238 0 361.5 -193t123.5 -559q0 -379 -119.5 -566t-365.5 -187q-236 0 -359 191.5t-123 561.5zM270 733q0 -319 75 -464.5t239 -145.5q166 0 240.5 147.5t74.5 462.5t-74.5 461.5t-240.5 146.5q-164 0 -239 -144.5t-75 -463.5z" /> +<glyph unicode="1" d="M188 1163l387 299h140v-1462h-162v1042q0 130 8 246q-21 -21 -47 -44t-238 -195z" /> +<glyph unicode="2" d="M100 0v143l385 387q176 178 232 254t84 148t28 155q0 117 -71 185.5t-197 68.5q-91 0 -172.5 -30t-181.5 -109l-88 113q202 168 440 168q206 0 323 -105.5t117 -283.5q0 -139 -78 -275t-292 -344l-320 -313v-8h752v-154h-961z" /> +<glyph unicode="3" d="M94 59v158q95 -47 202.5 -71.5t203.5 -24.5q379 0 379 297q0 266 -418 266h-144v143h146q171 0 271 75.5t100 209.5q0 107 -73.5 168t-199.5 61q-96 0 -181 -26t-194 -96l-84 112q90 71 207.5 111.5t247.5 40.5q213 0 331 -97.5t118 -267.5q0 -140 -78.5 -229 t-222.5 -119v-8q176 -22 261 -112t85 -236q0 -209 -145 -321.5t-412 -112.5q-116 0 -212.5 17.5t-187.5 61.5z" /> +<glyph unicode="4" d="M43 336v145l694 989h176v-983h217v-151h-217v-336h-159v336h-711zM209 487h545v486q0 143 10 323h-8q-48 -96 -90 -159z" /> +<glyph unicode="5" d="M133 59v160q70 -45 174 -70.5t205 -25.5q176 0 273.5 83t97.5 240q0 306 -375 306q-95 0 -254 -29l-86 55l55 684h727v-153h-585l-37 -439q115 23 229 23q231 0 363.5 -114.5t132.5 -313.5q0 -227 -144.5 -356t-398.5 -129q-247 0 -377 79z" /> +<glyph unicode="6" d="M117 625q0 431 167.5 644.5t495.5 213.5q113 0 178 -19v-143q-77 25 -176 25q-235 0 -359 -146.5t-136 -460.5h12q110 172 348 172q197 0 310.5 -119t113.5 -323q0 -228 -124.5 -358.5t-336.5 -130.5q-227 0 -360 170.5t-133 474.5zM287 506q0 -103 40 -192t113.5 -141 t167.5 -52q142 0 220.5 89.5t78.5 258.5q0 145 -73 228t-218 83q-90 0 -165 -37t-119.5 -102t-44.5 -135z" /> +<glyph unicode="7" d="M94 1309v153h973v-133l-598 -1329h-184l606 1309h-797z" /> +<glyph unicode="8" d="M104 373q0 251 306 391q-138 78 -198 168.5t-60 202.5q0 159 117.5 253.5t314.5 94.5q200 0 317 -93t117 -257q0 -108 -67 -197t-214 -162q178 -85 253 -178.5t75 -216.5q0 -182 -127 -290.5t-348 -108.5q-234 0 -360 102.5t-126 290.5zM268 369q0 -120 83.5 -187 t234.5 -67q149 0 232 70t83 192q0 97 -78 172.5t-272 146.5q-149 -64 -216 -141.5t-67 -185.5zM315 1128q0 -92 59 -158t218 -132q143 60 202.5 129t59.5 161q0 101 -72.5 160.5t-199.5 59.5q-125 0 -196 -60t-71 -160z" /> +<glyph unicode="9" d="M106 991q0 228 127.5 360t335.5 132q149 0 260.5 -76.5t171.5 -223t60 -345.5q0 -858 -664 -858q-116 0 -184 20v143q80 -26 182 -26q240 0 362.5 148.5t133.5 455.5h-12q-55 -83 -146 -126.5t-205 -43.5q-194 0 -308 116t-114 324zM270 993q0 -144 72 -226.5t219 -82.5 q91 0 167.5 37t120.5 101t44 134q0 105 -41 194t-114.5 140t-168.5 51q-143 0 -221 -92t-78 -256z" /> +<glyph unicode=":" horiz-adv-x="545" d="M152 106q0 67 30.5 101.5t87.5 34.5q58 0 90.5 -34.5t32.5 -101.5q0 -65 -33 -100t-90 -35q-51 0 -84.5 31.5t-33.5 103.5zM152 989q0 135 118 135q123 0 123 -135q0 -65 -33 -100t-90 -35q-51 0 -84.5 31.5t-33.5 103.5z" /> +<glyph unicode=";" horiz-adv-x="545" d="M63 -264q27 104 59.5 257t45.5 245h182l15 -23q-26 -100 -75 -232.5t-102 -246.5h-125zM147 989q0 135 119 135q123 0 123 -135q0 -65 -33 -100t-90 -35q-58 0 -88.5 35t-30.5 100z" /> +<glyph unicode="&#x3c;" d="M104 664v98l961 479v-149l-782 -371l782 -328v-151z" /> +<glyph unicode="=" d="M119 449v137h930v-137h-930zM119 858v137h930v-137h-930z" /> +<glyph unicode="&#x3e;" d="M104 242v151l783 326l-783 373v149l961 -479v-98z" /> +<glyph unicode="?" horiz-adv-x="879" d="M27 1384q189 99 395 99q191 0 297 -94t106 -265q0 -73 -19.5 -128.5t-57.5 -105t-164 -159.5q-101 -86 -133.5 -143t-32.5 -152v-33h-129v54q0 117 36 192.5t134 159.5q136 115 171.5 173t35.5 140q0 102 -65.5 157.5t-188.5 55.5q-79 0 -154 -18.5t-172 -67.5zM240 106 q0 136 120 136q58 0 89.5 -35t31.5 -101q0 -64 -32 -99.5t-89 -35.5q-52 0 -86 31.5t-34 103.5z" /> +<glyph unicode="@" horiz-adv-x="1841" d="M121 571q0 260 107 463t305 314.5t454 111.5q215 0 382.5 -90.5t259 -257t91.5 -383.5q0 -142 -44 -260t-124 -183t-184 -65q-86 0 -145 52t-70 133h-8q-40 -87 -114.5 -136t-176.5 -49q-150 0 -234.5 102.5t-84.5 278.5q0 204 118 331.5t310 127.5q68 0 154 -12.5 t155 -34.5l-25 -470v-22q0 -178 133 -178q91 0 148 107.5t57 279.5q0 181 -74 317t-210.5 209.5t-313.5 73.5q-223 0 -388 -92.5t-252 -264t-87 -396.5q0 -305 161 -469t464 -164q210 0 436 86v-133q-192 -84 -436 -84q-363 0 -563.5 199.5t-200.5 557.5zM686 598 q0 -254 195 -254q207 0 225 313l14 261q-72 20 -157 20q-130 0 -203.5 -90t-73.5 -250z" /> +<glyph unicode="A" horiz-adv-x="1296" d="M0 0l578 1468h143l575 -1468h-176l-182 465h-586l-180 -465h-172zM412 618h473l-170 453q-33 86 -68 211q-22 -96 -63 -211z" /> +<glyph unicode="B" horiz-adv-x="1327" d="M201 0v1462h413q291 0 421 -87t130 -275q0 -130 -72.5 -214.5t-211.5 -109.5v-10q333 -57 333 -350q0 -196 -132.5 -306t-370.5 -110h-510zM371 145h305q177 0 266.5 68.5t89.5 214.5q0 136 -91.5 200t-278.5 64h-291v-547zM371 836h280q180 0 259 56.5t79 190.5 q0 123 -88 177.5t-280 54.5h-250v-479z" /> +<glyph unicode="C" horiz-adv-x="1292" d="M125 733q0 226 84.5 396t244 262t375.5 92q230 0 402 -84l-72 -146q-166 78 -332 78q-241 0 -380.5 -160.5t-139.5 -439.5q0 -287 134.5 -443.5t383.5 -156.5q153 0 349 55v-149q-152 -57 -375 -57q-323 0 -498.5 196t-175.5 557z" /> +<glyph unicode="D" horiz-adv-x="1493" d="M201 0v1462h448q341 0 530 -189t189 -528q0 -362 -196.5 -553.5t-565.5 -191.5h-405zM371 147h207q304 0 457 149.5t153 442.5q0 286 -143.5 431t-426.5 145h-247v-1168z" /> +<glyph unicode="E" horiz-adv-x="1139" d="M201 0v1462h815v-151h-645v-471h606v-150h-606v-538h645v-152h-815z" /> +<glyph unicode="F" horiz-adv-x="1057" d="M201 0v1462h815v-151h-645v-535h606v-151h-606v-625h-170z" /> +<glyph unicode="G" horiz-adv-x="1491" d="M125 731q0 228 91.5 399.5t263.5 262t403 90.5q234 0 436 -86l-66 -150q-198 84 -381 84q-267 0 -417 -159t-150 -441q0 -296 144.5 -449t424.5 -153q152 0 297 35v450h-327v152h497v-711q-116 -37 -236 -56t-278 -19q-332 0 -517 197.5t-185 553.5z" /> +<glyph unicode="H" horiz-adv-x="1511" d="M201 0v1462h170v-622h770v622h170v-1462h-170v688h-770v-688h-170z" /> +<glyph unicode="I" horiz-adv-x="571" d="M201 0v1462h170v-1462h-170z" /> +<glyph unicode="J" horiz-adv-x="547" d="M-160 -213q71 -20 148 -20q99 0 150.5 60t51.5 173v1462h170v-1448q0 -190 -96 -294.5t-276 -104.5q-94 0 -148 27v145z" /> +<glyph unicode="K" horiz-adv-x="1257" d="M201 0v1462h170v-725l663 725h201l-588 -635l610 -827h-200l-533 709l-153 -136v-573h-170z" /> +<glyph unicode="L" horiz-adv-x="1063" d="M201 0v1462h170v-1308h645v-154h-815z" /> +<glyph unicode="M" horiz-adv-x="1849" d="M201 0v1462h256l463 -1206h8l467 1206h254v-1462h-170v942q0 162 14 352h-8l-500 -1294h-137l-496 1296h-8q14 -154 14 -366v-930h-157z" /> +<glyph unicode="N" horiz-adv-x="1544" d="M201 0v1462h192l797 -1222h8q-2 28 -9 174q-5 114 -5 177v32v839h159v-1462h-194l-799 1227h-8q16 -216 16 -396v-831h-157z" /> +<glyph unicode="O" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q315 0 492 -200t177 -552q0 -351 -177.5 -552t-493.5 -201q-323 0 -498.5 197.5t-175.5 557.5zM305 733q0 -297 126.5 -450.5t367.5 -153.5q243 0 367 153t124 451q0 295 -123.5 447.5t-365.5 152.5q-243 0 -369.5 -153.5 t-126.5 -446.5z" /> +<glyph unicode="P" horiz-adv-x="1233" d="M201 0v1462h379q548 0 548 -426q0 -222 -151.5 -341.5t-433.5 -119.5h-172v-575h-170zM371 721h153q226 0 327 73t101 234q0 145 -95 216t-296 71h-190v-594z" /> +<glyph unicode="Q" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q315 0 492 -200t177 -552q0 -281 -113 -467t-319 -252l348 -362h-247l-285 330l-55 -2q-323 0 -498.5 197.5t-175.5 557.5zM305 733q0 -297 126.5 -450.5t367.5 -153.5q243 0 367 153t124 451q0 295 -123.5 447.5t-365.5 152.5 q-243 0 -369.5 -153.5t-126.5 -446.5z" /> +<glyph unicode="R" horiz-adv-x="1266" d="M201 0v1462h401q269 0 397.5 -103t128.5 -310q0 -290 -294 -392l397 -657h-201l-354 608h-305v-608h-170zM371 754h233q180 0 264 71.5t84 214.5q0 145 -85.5 209t-274.5 64h-221v-559z" /> +<glyph unicode="S" horiz-adv-x="1124" d="M106 47v164q90 -38 196 -60t210 -22q170 0 256 64.5t86 179.5q0 76 -30.5 124.5t-102 89.5t-217.5 93q-204 73 -291.5 173t-87.5 261q0 169 127 269t336 100q218 0 401 -80l-53 -148q-181 76 -352 76q-135 0 -211 -58t-76 -161q0 -76 28 -124.5t94.5 -89t203.5 -89.5 q230 -82 316.5 -176t86.5 -244q0 -193 -140 -301t-380 -108q-260 0 -400 67z" /> +<glyph unicode="T" horiz-adv-x="1133" d="M18 1311v151h1096v-151h-463v-1311h-170v1311h-463z" /> +<glyph unicode="U" horiz-adv-x="1491" d="M186 520v942h170v-954q0 -183 100 -281t294 -98q185 0 285 98.5t100 282.5v952h170v-946q0 -250 -151 -393t-415 -143t-408.5 144t-144.5 396z" /> +<glyph unicode="V" horiz-adv-x="1219" d="M0 1462h180l336 -946q58 -163 92 -317q36 162 94 323l334 940h183l-527 -1462h-168z" /> +<glyph unicode="W" horiz-adv-x="1896" d="M27 1462h180l231 -903q48 -190 70 -344q27 183 80 358l262 889h180l275 -897q48 -155 81 -350q19 142 72 346l230 901h180l-391 -1462h-168l-295 979q-21 65 -47 164t-27 119q-22 -132 -70 -289l-286 -973h-168z" /> +<glyph unicode="X" horiz-adv-x="1182" d="M8 0l486 764l-453 698h188l363 -579l366 579h181l-453 -692l488 -770h-193l-393 643l-400 -643h-180z" /> +<glyph unicode="Y" horiz-adv-x="1147" d="M0 1462h186l387 -731l390 731h184l-488 -895v-567h-172v559z" /> +<glyph unicode="Z" horiz-adv-x="1169" d="M82 0v133l776 1176h-752v153h959v-133l-776 -1175h798v-154h-1005z" /> +<glyph unicode="[" horiz-adv-x="674" d="M166 -324v1786h457v-141h-289v-1503h289v-142h-457z" /> +<glyph unicode="\" horiz-adv-x="752" d="M23 1462h163l547 -1462h-166z" /> +<glyph unicode="]" horiz-adv-x="674" d="M51 -182h289v1503h-289v141h457v-1786h-457v142z" /> +<glyph unicode="^" horiz-adv-x="1110" d="M49 551l434 922h99l477 -922h-152l-372 745l-334 -745h-152z" /> +<glyph unicode="_" horiz-adv-x="918" d="M-4 -184h926v-131h-926v131z" /> +<glyph unicode="`" horiz-adv-x="1182" d="M393 1548v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="a" horiz-adv-x="1139" d="M94 303q0 332 531 348l186 6v68q0 129 -55.5 190.5t-177.5 61.5q-137 0 -310 -84l-51 127q81 44 177.5 69t193.5 25q196 0 290.5 -87t94.5 -279v-748h-123l-33 156h-8q-82 -103 -163.5 -139.5t-203.5 -36.5q-163 0 -255.5 84t-92.5 239zM268 301q0 -90 54.5 -137 t152.5 -47q155 0 243.5 85t88.5 238v99l-166 -7q-198 -7 -285.5 -61.5t-87.5 -169.5z" /> +<glyph unicode="b" horiz-adv-x="1255" d="M176 0v1556h166v-378q0 -127 -8 -228h8q116 164 344 164q216 0 335.5 -147.5t119.5 -417.5t-120.5 -419.5t-334.5 -149.5q-107 0 -195.5 39.5t-148.5 121.5h-12l-35 -141h-119zM342 549q0 -231 77 -330.5t247 -99.5q153 0 228 111.5t75 320.5q0 214 -75 319t-232 105 q-170 0 -245 -97.5t-75 -328.5z" /> +<glyph unicode="c" horiz-adv-x="975" d="M115 541q0 275 132.5 425t377.5 150q79 0 158 -17t124 -40l-51 -141q-55 22 -120 36.5t-115 14.5q-334 0 -334 -426q0 -202 81.5 -310t241.5 -108q137 0 281 59v-147q-110 -57 -277 -57q-238 0 -368.5 146.5t-130.5 414.5z" /> +<glyph unicode="d" horiz-adv-x="1255" d="M115 545q0 271 120 421t334 150q223 0 342 -162h13l-7 79l-4 77v446h166v-1556h-135l-22 147h-9q-115 -167 -344 -167q-215 0 -334.5 147t-119.5 418zM287 543q0 -210 77 -317t226 -107q170 0 246.5 92.5t76.5 298.5v35q0 233 -77.5 332.5t-247.5 99.5 q-146 0 -223.5 -113.5t-77.5 -320.5z" /> +<glyph unicode="e" horiz-adv-x="1149" d="M115 539q0 265 130.5 421t350.5 156q206 0 326 -135.5t120 -357.5v-105h-755q5 -193 97.5 -293t260.5 -100q177 0 350 74v-148q-88 -38 -166.5 -54.5t-189.5 -16.5q-243 0 -383.5 148t-140.5 411zM291 653h573q0 157 -70 240.5t-200 83.5q-132 0 -210.5 -86t-92.5 -238z " /> +<glyph unicode="f" horiz-adv-x="694" d="M29 967v75l196 60v61q0 404 353 404q87 0 204 -35l-43 -133q-96 31 -164 31q-94 0 -139 -62.5t-45 -200.5v-71h279v-129h-279v-967h-166v967h-196z" /> +<glyph unicode="g" horiz-adv-x="1122" d="M39 -186q0 100 64 173t180 99q-42 19 -70.5 59t-28.5 93q0 60 32 105t101 87q-85 35 -138.5 119t-53.5 192q0 180 108 277.5t306 97.5q86 0 155 -20h379v-105l-203 -24q28 -35 50 -91.5t22 -127.5q0 -161 -110 -257t-302 -96q-49 0 -92 8q-106 -56 -106 -141 q0 -45 37 -66.5t127 -21.5h194q178 0 273.5 -75t95.5 -218q0 -182 -146 -277.5t-426 -95.5q-215 0 -331.5 80t-116.5 226zM199 -184q0 -89 75 -135t215 -46q209 0 309.5 62.5t100.5 169.5q0 89 -55 123.5t-207 34.5h-199q-113 0 -176 -54t-63 -155zM289 745q0 -115 65 -174 t181 -59q243 0 243 236q0 247 -246 247q-117 0 -180 -63t-63 -187z" /> +<glyph unicode="h" horiz-adv-x="1257" d="M176 0v1556h166v-471q0 -85 -8 -141h10q49 79 139.5 124.5t206.5 45.5q201 0 301.5 -95.5t100.5 -303.5v-715h-166v709q0 134 -61 200t-191 66q-173 0 -252.5 -94t-79.5 -308v-573h-166z" /> +<glyph unicode="i" horiz-adv-x="518" d="M162 1393q0 57 28 83.5t70 26.5q40 0 69 -27t29 -83t-29 -83.5t-69 -27.5q-42 0 -70 27.5t-28 83.5zM176 0v1096h166v-1096h-166z" /> +<glyph unicode="j" horiz-adv-x="518" d="M-111 -332q69 -20 136 -20q78 0 114.5 42.5t36.5 129.5v1276h166v-1264q0 -324 -299 -324q-95 0 -154 25v135zM162 1393q0 57 28 83.5t70 26.5q40 0 69 -27t29 -83t-29 -83.5t-69 -27.5q-42 0 -70 27.5t-28 83.5z" /> +<glyph unicode="k" horiz-adv-x="1075" d="M176 0v1556h164v-825q0 -55 -8 -170h8q43 61 131 160l354 375h197l-444 -467l475 -629h-201l-387 518l-125 -108v-410h-164z" /> +<glyph unicode="l" horiz-adv-x="518" d="M176 0v1556h166v-1556h-166z" /> +<glyph unicode="m" horiz-adv-x="1905" d="M176 0v1096h135l27 -150h8q47 80 132.5 125t191.5 45q257 0 336 -186h8q49 86 142 136t212 50q186 0 278.5 -95.5t92.5 -305.5v-715h-166v713q0 131 -56 196.5t-174 65.5q-155 0 -229 -89t-74 -274v-612h-166v713q0 131 -56 196.5t-175 65.5q-156 0 -228.5 -93.5 t-72.5 -306.5v-575h-166z" /> +<glyph unicode="n" horiz-adv-x="1257" d="M176 0v1096h135l27 -150h8q51 81 143 125.5t205 44.5q198 0 298 -95.5t100 -305.5v-715h-166v709q0 134 -61 200t-191 66q-172 0 -252 -93t-80 -307v-575h-166z" /> +<glyph unicode="o" horiz-adv-x="1237" d="M115 549q0 268 134 417.5t372 149.5q230 0 365.5 -153t135.5 -414q0 -268 -135 -418.5t-373 -150.5q-147 0 -261 69t-176 198t-62 302zM287 549q0 -210 84 -320t247 -110t247.5 109.5t84.5 320.5q0 209 -84.5 317.5t-249.5 108.5q-163 0 -246 -107t-83 -319z" /> +<glyph unicode="p" horiz-adv-x="1255" d="M176 -492v1588h135l23 -150h8q64 90 149 130t195 40q218 0 336.5 -149t118.5 -418q0 -270 -120.5 -419.5t-334.5 -149.5q-107 0 -195.5 39.5t-148.5 121.5h-12q12 -96 12 -182v-451h-166zM342 549q0 -231 77 -330.5t247 -99.5q142 0 222.5 115t80.5 317 q0 205 -80.5 314.5t-226.5 109.5q-168 0 -243 -93t-77 -296v-37z" /> +<glyph unicode="q" horiz-adv-x="1255" d="M115 545q0 269 120 420t334 151q225 0 346 -170h9l24 150h131v-1588h-166v469q0 100 11 170h-13q-115 -167 -346 -167q-212 0 -331 149t-119 416zM287 543q0 -207 76.5 -315.5t226.5 -108.5q166 0 242 89t81 300v37q0 230 -78 331t-247 101q-146 0 -223.5 -113.5 t-77.5 -320.5z" /> +<glyph unicode="r" horiz-adv-x="836" d="M176 0v1096h137l19 -203h8q61 107 147 165t189 58q73 0 131 -12l-23 -154q-68 15 -120 15q-133 0 -227.5 -108t-94.5 -269v-588h-166z" /> +<glyph unicode="s" horiz-adv-x="977" d="M106 827q0 134 109 211.5t299 77.5q177 0 346 -72l-59 -135q-165 68 -299 68q-118 0 -178 -37t-60 -102q0 -44 22.5 -75t72.5 -59t192 -81q195 -71 263.5 -143t68.5 -181q0 -153 -114 -236t-320 -83q-218 0 -340 69v154q79 -40 169.5 -63t174.5 -23q130 0 200 41.5 t70 126.5q0 64 -55.5 109.5t-216.5 107.5q-153 57 -217.5 99.5t-96 96.5t-31.5 129z" /> +<glyph unicode="t" horiz-adv-x="723" d="M31 967v80l157 69l70 234h96v-254h318v-129h-318v-645q0 -99 47 -152t129 -53q44 0 85 6.5t65 13.5v-127q-27 -13 -79.5 -21.5t-94.5 -8.5q-318 0 -318 335v652h-157z" /> +<glyph unicode="u" horiz-adv-x="1257" d="M164 379v717h168v-711q0 -134 61 -200t191 -66q172 0 251.5 94t79.5 307v576h166v-1096h-137l-24 147h-9q-51 -81 -141.5 -124t-206.5 -43q-200 0 -299.5 95t-99.5 304z" /> +<glyph unicode="v" horiz-adv-x="1026" d="M0 1096h178l236 -650q80 -228 94 -296h8q11 53 69.5 219.5t262.5 726.5h178l-416 -1096h-194z" /> +<glyph unicode="w" horiz-adv-x="1593" d="M23 1096h174q106 -413 161.5 -629t63.5 -291h8q11 57 35.5 147.5t42.5 143.5l201 629h180l196 -629q56 -172 76 -289h8q4 36 21.5 111t208.5 807h172l-303 -1096h-197l-201 643q-19 59 -71 268h-8q-40 -175 -70 -270l-207 -641h-192z" /> +<glyph unicode="x" horiz-adv-x="1073" d="M39 0l401 561l-381 535h189l289 -420l288 420h187l-381 -535l401 -561h-188l-307 444l-310 -444h-188z" /> +<glyph unicode="y" horiz-adv-x="1032" d="M2 1096h178l240 -625q79 -214 98 -309h8q13 51 54.5 174.5t271.5 759.5h178l-471 -1248q-70 -185 -163.5 -262.5t-229.5 -77.5q-76 0 -150 17v133q55 -12 123 -12q171 0 244 192l61 156z" /> +<glyph unicode="z" horiz-adv-x="958" d="M82 0v113l598 854h-561v129h743v-129l-590 -838h605v-129h-795z" /> +<glyph unicode="{" horiz-adv-x="776" d="M61 498v141q130 2 188 48t58 142v306q0 155 108 241t290 86v-139q-230 -6 -230 -199v-295q0 -215 -223 -254v-12q223 -39 223 -254v-297q0 -102 58.5 -148t171.5 -48v-140q-190 2 -294 87t-104 239v303q0 104 -63 148.5t-183 44.5z" /> +<glyph unicode="|" horiz-adv-x="1128" d="M494 -496v2052h141v-2052h-141z" /> +<glyph unicode="}" horiz-adv-x="776" d="M72 -184q111 2 169 48t58 148v297q0 114 55 174t168 80v12q-223 39 -223 254v295q0 193 -227 199v139q184 0 289.5 -87t105.5 -240v-306q0 -97 59 -142.5t189 -47.5v-141q-122 0 -185 -44.5t-63 -148.5v-303q0 -153 -102.5 -238.5t-292.5 -87.5v140z" /> +<glyph unicode="~" d="M104 592v151q100 109 244 109q68 0 124.5 -14t145.5 -52q66 -28 115 -41.5t96 -13.5q54 0 118 32t118 89v-150q-102 -110 -244 -110q-72 0 -135 16.5t-135 48.5q-75 32 -120 44t-93 12q-53 0 -116.5 -33.5t-117.5 -87.5z" /> +<glyph unicode="&#xa1;" horiz-adv-x="547" d="M152 983q0 63 31.5 99t88.5 36q51 0 86 -32t35 -103q0 -135 -121 -135q-60 0 -90 35.5t-30 99.5zM168 -373l51 1057h105l51 -1057h-207z" /> +<glyph unicode="&#xa2;" d="M190 741q0 508 396 570v172h135v-164q75 -3 146 -19.5t120 -39.5l-49 -140q-133 51 -242 51q-172 0 -253 -105.5t-81 -322.5q0 -212 79.5 -313.5t246.5 -101.5q141 0 283 59v-147q-105 -54 -252 -60v-200h-133v206q-203 32 -299.5 168.5t-96.5 386.5z" /> +<glyph unicode="&#xa3;" d="M63 0v141q205 47 205 291v223h-198v127h198v316q0 178 112 280.5t302 102.5t360 -84l-61 -133q-154 77 -297 77q-123 0 -185.5 -62t-62.5 -202v-295h422v-127h-422v-221q0 -100 -32.5 -168t-106.5 -112h795v-154h-1029z" /> +<glyph unicode="&#xa4;" d="M123 1092l94 92l135 -133q104 73 234 73q127 0 229 -73l137 133l95 -92l-134 -138q74 -113 74 -231q0 -131 -74 -234l131 -135l-92 -92l-137 133q-102 -71 -229 -71q-134 0 -234 73l-135 -133l-92 92l133 136q-74 107 -74 231q0 122 74 229zM313 723q0 -112 78.5 -192 t194.5 -80t195 79.5t79 192.5q0 114 -80 195t-194 81q-116 0 -194.5 -82t-78.5 -194z" /> +<glyph unicode="&#xa5;" d="M31 1462h178l375 -727l379 727h174l-416 -770h262v-127h-317v-170h317v-127h-317v-268h-164v268h-316v127h316v170h-316v127h256z" /> +<glyph unicode="&#xa6;" horiz-adv-x="1128" d="M494 281h141v-777h-141v777zM494 780v776h141v-776h-141z" /> +<glyph unicode="&#xa7;" horiz-adv-x="1057" d="M123 57v148q78 -37 175 -59.5t179 -22.5q134 0 204.5 38t70.5 109q0 46 -24 75t-78 58t-169 72q-142 52 -209 97t-100 102t-33 135q0 86 43 154.5t121 105.5q-74 40 -116 95.5t-42 140.5q0 121 103.5 190.5t300.5 69.5q94 0 173.5 -14.5t176.5 -53.5l-53 -131 q-98 39 -165.5 52.5t-143.5 13.5q-116 0 -174 -29.5t-58 -93.5q0 -60 61.5 -102t215.5 -97q186 -68 261 -143.5t75 -182.5q0 -90 -41 -160.5t-115 -111.5q153 -81 153 -227q0 -140 -117 -216.5t-329 -76.5q-218 0 -346 65zM285 829q0 -77 66 -129.5t233 -113.5l49 -19 q137 80 137 191q0 83 -73.5 139t-258.5 113q-68 -19 -110.5 -69t-42.5 -112z" /> +<glyph unicode="&#xa8;" horiz-adv-x="1182" d="M309 1393q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM690 1393q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="&#xa9;" horiz-adv-x="1704" d="M100 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM205 731q0 -173 87 -323.5t237.5 -237t322.5 -86.5q174 0 323 87t236.5 235.5t87.5 324.5q0 174 -87 323 t-235.5 236.5t-324.5 87.5q-174 0 -323 -87t-236.5 -235.5t-87.5 -324.5zM481 731q0 209 110.5 332t301.5 123q128 0 246 -60l-58 -118q-108 51 -188 51q-125 0 -192.5 -87t-67.5 -241q0 -168 63.5 -249t194.5 -81q86 0 211 45v-124q-48 -20 -98.5 -34t-120.5 -14 q-194 0 -298 120.5t-104 336.5z" /> +<glyph unicode="&#xaa;" horiz-adv-x="725" d="M70 989q0 102 77 154.5t242 58.5l117 4v39q0 133 -148 133q-100 0 -204 -51l-43 96q114 56 247 56q130 0 198.5 -52.5t68.5 -173.5v-452h-93l-24 84q-92 -97 -232 -97q-95 0 -150.5 49.5t-55.5 151.5zM193 989q0 -100 112 -100q201 0 201 180v49l-98 -4 q-112 -4 -163.5 -32.5t-51.5 -92.5z" /> +<glyph unicode="&#xab;" horiz-adv-x="1018" d="M82 524v27l342 407l119 -69l-289 -350l289 -351l-119 -71zM477 524v27l344 407l117 -69l-287 -350l287 -351l-117 -71z" /> +<glyph unicode="&#xac;" d="M104 653v138h961v-527h-137v389h-824z" /> +<glyph unicode="&#xad;" horiz-adv-x="659" d="M84 473v152h491v-152h-491z" /> +<glyph unicode="&#xae;" horiz-adv-x="1704" d="M100 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM205 731q0 -173 87 -323.5t237.5 -237t322.5 -86.5q174 0 323 87t236.5 235.5t87.5 324.5q0 174 -87 323 t-235.5 236.5t-324.5 87.5q-174 0 -323 -87t-236.5 -235.5t-87.5 -324.5zM575 285v891h261q166 0 243.5 -65t77.5 -198q0 -80 -42.5 -141.5t-119.5 -91.5l238 -395h-168l-207 354h-135v-354h-148zM723 762h108q80 0 128.5 41.5t48.5 105.5q0 75 -43 107.5t-136 32.5h-106 v-287z" /> +<glyph unicode="&#xaf;" horiz-adv-x="1024" d="M-6 1556v127h1036v-127h-1036z" /> +<glyph unicode="&#xb0;" horiz-adv-x="877" d="M127 1171q0 130 90.5 221t220.5 91t221 -90.5t91 -221.5q0 -84 -41 -155.5t-114 -113.5t-157 -42q-130 0 -220.5 90t-90.5 221zM242 1171q0 -82 58.5 -139t139.5 -57q80 0 137.5 56.5t57.5 139.5q0 84 -56.5 140.5t-138.5 56.5q-83 0 -140.5 -57t-57.5 -140z" /> +<glyph unicode="&#xb1;" d="M104 653v138h410v428h139v-428h412v-138h-412v-426h-139v426h-410zM104 1v138h961v-138h-961z" /> +<glyph unicode="&#xb2;" horiz-adv-x="711" d="M49 586v104l236 230q89 86 130 134.5t57.5 86.5t16.5 92q0 68 -40 102.5t-103 34.5q-52 0 -101 -19t-118 -69l-66 88q131 111 283 111q132 0 205.5 -65t73.5 -177q0 -80 -44.5 -155.5t-191.5 -213.5l-174 -165h440v-119h-604z" /> +<glyph unicode="&#xb3;" horiz-adv-x="711" d="M33 625v123q147 -68 270 -68q211 0 211 162q0 145 -231 145h-117v107h119q103 0 152.5 39.5t49.5 107.5q0 61 -40 95t-107 34q-66 0 -122 -21.5t-112 -56.5l-69 90q63 45 133 72t164 27q136 0 214.5 -59.5t78.5 -166.5q0 -80 -41 -131.5t-109 -74.5q176 -47 176 -209 q0 -128 -92 -199.5t-260 -71.5q-152 0 -268 56z" /> +<glyph unicode="&#xb4;" horiz-adv-x="1182" d="M393 1241v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="&#xb5;" horiz-adv-x="1268" d="M176 -492v1588h166v-715q0 -262 254 -262q171 0 250.5 94.5t79.5 306.5v576h166v-1096h-136l-26 147h-10q-111 -167 -340 -167q-150 0 -238 92h-10q10 -84 10 -244v-320h-166z" /> +<glyph unicode="&#xb6;" horiz-adv-x="1341" d="M113 1042q0 260 109 387t341 127h557v-1816h-114v1712h-213v-1712h-115v819q-62 -18 -146 -18q-216 0 -317.5 125t-101.5 376z" /> +<glyph unicode="&#xb7;" horiz-adv-x="545" d="M152 723q0 66 31 100.5t87 34.5q58 0 90.5 -34.5t32.5 -100.5q0 -65 -33 -100t-90 -35q-51 0 -84.5 31.5t-33.5 103.5z" /> +<glyph unicode="&#xb8;" horiz-adv-x="465" d="M37 -377q45 -8 104 -8q79 0 119.5 20t40.5 74q0 43 -39.5 69.5t-148.5 43.5l88 178h110l-55 -115q180 -39 180 -174q0 -97 -76.5 -150t-226.5 -53q-51 0 -96 9v106z" /> +<glyph unicode="&#xb9;" horiz-adv-x="711" d="M76 1280l262 182h143v-876h-133v579q0 91 6 181q-22 -22 -49 -44.5t-162 -117.5z" /> +<glyph unicode="&#xba;" horiz-adv-x="768" d="M66 1135q0 163 84 253.5t235 90.5q152 0 234.5 -91t82.5 -253q0 -164 -85.5 -255.5t-235.5 -91.5q-146 0 -230.5 93t-84.5 254zM188 1135q0 -122 45.5 -183t149.5 -61q105 0 151 61t46 183q0 123 -46 182t-151 59q-103 0 -149 -59t-46 -182z" /> +<glyph unicode="&#xbb;" horiz-adv-x="1018" d="M80 188l287 351l-287 350l117 69l344 -407v-27l-344 -407zM475 188l287 351l-287 350l117 69l344 -407v-27l-344 -407z" /> +<glyph unicode="&#xbc;" horiz-adv-x="1597" d="M252 0l903 1462h143l-903 -1462h-143zM75 1280l262 182h143v-876h-133v579q0 91 6 181q-22 -22 -49 -44.5t-162 -117.5zM817 203v101l408 579h139v-563h125v-117h-125v-202h-145v202h-402zM957 320h262v195q0 134 6 209q-5 -12 -17 -31.5t-27 -41.5l-30 -46 q-15 -22 -26 -39z" /> +<glyph unicode="&#xbd;" horiz-adv-x="1597" d="M184 0l903 1462h143l-903 -1462h-143zM46 1280l262 182h143v-876h-133v579q0 91 6 181q-22 -22 -49 -44.5t-162 -117.5zM895 1v104l236 230q89 86 130 134.5t57.5 86.5t16.5 92q0 68 -40 102.5t-103 34.5q-52 0 -101 -19t-118 -69l-66 88q131 111 283 111 q132 0 205.5 -65t73.5 -177q0 -80 -44.5 -155.5t-191.5 -213.5l-174 -165h440v-119h-604z" /> +<glyph unicode="&#xbe;" horiz-adv-x="1597" d="M26 625v123q147 -68 270 -68q211 0 211 162q0 145 -231 145h-117v107h119q103 0 152.5 39.5t49.5 107.5q0 61 -40 95t-107 34q-66 0 -122 -21.5t-112 -56.5l-69 90q63 45 133 72t164 27q136 0 214.5 -59.5t78.5 -166.5q0 -80 -41 -131.5t-109 -74.5q176 -47 176 -209 q0 -128 -92 -199.5t-260 -71.5q-152 0 -268 56zM344 0l903 1462h143l-903 -1462h-143zM897 203v101l408 579h139v-563h125v-117h-125v-202h-145v202h-402zM1037 320h262v195q0 134 6 209q-5 -12 -17 -31.5t-27 -41.5l-30 -46q-15 -22 -26 -39z" /> +<glyph unicode="&#xbf;" horiz-adv-x="879" d="M51 -37q0 70 17.5 122.5t49.5 97t76.5 85.5t98.5 88q101 88 133.5 146t32.5 151v31h131v-51q0 -122 -37.5 -196t-134.5 -158q-121 -106 -151.5 -143.5t-43 -76t-12.5 -94.5q0 -100 66 -156.5t188 -56.5q80 0 155 19t173 67l59 -135q-197 -96 -395 -96q-190 0 -298 93 t-108 263zM397 983q0 64 33 99.5t88 35.5q51 0 86 -32t35 -103q0 -135 -121 -135q-59 0 -90 34.5t-31 100.5z" /> +<glyph unicode="&#xc0;" horiz-adv-x="1296" d="M0 0l578 1468h143l575 -1468h-176l-182 465h-586l-180 -465h-172zM412 618h473l-170 453q-33 86 -68 211q-22 -96 -63 -211zM331 1886v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="&#xc1;" horiz-adv-x="1296" d="M0 0l578 1468h143l575 -1468h-176l-182 465h-586l-180 -465h-172zM412 618h473l-170 453q-33 86 -68 211q-22 -96 -63 -211zM526 1579v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="&#xc2;" horiz-adv-x="1296" d="M0 0l578 1468h143l575 -1468h-176l-182 465h-586l-180 -465h-172zM412 618h473l-170 453q-33 86 -68 211q-22 -96 -63 -211zM303 1579v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115z" /> +<glyph unicode="&#xc3;" horiz-adv-x="1296" d="M0 0l578 1468h143l575 -1468h-176l-182 465h-586l-180 -465h-172zM412 618h473l-170 453q-33 86 -68 211q-22 -96 -63 -211zM268 1579q13 121 70.5 189.5t148.5 68.5q46 0 89 -18.5t82 -41t75 -41t68 -18.5q49 0 73 29.5t39 91.5h99q-13 -121 -69.5 -189.5t-150.5 -68.5 q-43 0 -84 18.5t-80.5 41t-76 41t-70.5 18.5q-50 0 -75.5 -30t-39.5 -91h-98z" /> +<glyph unicode="&#xc4;" horiz-adv-x="1296" d="M0 0l578 1468h143l575 -1468h-176l-182 465h-586l-180 -465h-172zM412 618h473l-170 453q-33 86 -68 211q-22 -96 -63 -211zM364 1731q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM745 1731q0 52 26.5 75 t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="&#xc5;" horiz-adv-x="1296" d="M0 0l578 1468h143l575 -1468h-176l-182 465h-586l-180 -465h-172zM412 618h473l-170 453q-33 86 -68 211q-22 -96 -63 -211zM424 1585q0 98 60.5 155.5t160.5 57.5q101 0 163 -59.5t62 -151.5q0 -98 -61.5 -157.5t-163.5 -59.5q-101 0 -161 58.5t-60 156.5zM528 1585 q0 -56 30 -86.5t87 -30.5q52 0 84.5 30.5t32.5 86.5t-33 86.5t-84 30.5t-84 -30.5t-33 -86.5z" /> +<glyph unicode="&#xc6;" horiz-adv-x="1788" d="M-2 0l698 1462h969v-151h-580v-471h541v-150h-541v-538h580v-152h-750v465h-514l-227 -465h-176zM469 618h446v693h-118z" /> +<glyph unicode="&#xc7;" horiz-adv-x="1292" d="M125 733q0 226 84.5 396t244 262t375.5 92q230 0 402 -84l-72 -146q-166 78 -332 78q-241 0 -380.5 -160.5t-139.5 -439.5q0 -287 134.5 -443.5t383.5 -156.5q153 0 349 55v-149q-152 -57 -375 -57q-323 0 -498.5 196t-175.5 557zM551 -377q45 -8 104 -8q79 0 119.5 20 t40.5 74q0 43 -39.5 69.5t-148.5 43.5l88 178h110l-55 -115q180 -39 180 -174q0 -97 -76.5 -150t-226.5 -53q-51 0 -96 9v106z" /> +<glyph unicode="&#xc8;" horiz-adv-x="1139" d="M201 0v1462h815v-151h-645v-471h606v-150h-606v-538h645v-152h-815zM320 1886v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="&#xc9;" horiz-adv-x="1139" d="M201 0v1462h815v-151h-645v-471h606v-150h-606v-538h645v-152h-815zM456 1579v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="&#xca;" horiz-adv-x="1139" d="M201 0v1462h815v-151h-645v-471h606v-150h-606v-538h645v-152h-815zM263 1579v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115z" /> +<glyph unicode="&#xcb;" horiz-adv-x="1139" d="M201 0v1462h815v-151h-645v-471h606v-150h-606v-538h645v-152h-815zM327 1731q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM708 1731q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5 t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="&#xcc;" horiz-adv-x="571" d="M201 0v1462h170v-1462h-170zM5 1886v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="&#xcd;" horiz-adv-x="571" d="M201 0v1462h170v-1462h-170zM179 1579v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="&#xce;" horiz-adv-x="571" d="M201 0v1462h170v-1462h-170zM-57 1579v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115z" /> +<glyph unicode="&#xcf;" horiz-adv-x="571" d="M201 0v1462h170v-1462h-170zM5 1731q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM386 1731q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="&#xd0;" horiz-adv-x="1479" d="M47 649v150h154v663h434q337 0 527 -187.5t190 -529.5q0 -362 -196.5 -553.5t-565.5 -191.5h-389v649h-154zM371 147h190q610 0 610 592q0 576 -569 576h-231v-516h379v-150h-379v-502z" /> +<glyph unicode="&#xd1;" horiz-adv-x="1544" d="M201 0v1462h192l797 -1222h8q-2 28 -9 174q-5 114 -5 177v32v839h159v-1462h-194l-799 1227h-8q16 -216 16 -396v-831h-157zM411 1579q13 121 70.5 189.5t148.5 68.5q46 0 89 -18.5t82 -41t75 -41t68 -18.5q49 0 73 29.5t39 91.5h99q-13 -121 -69.5 -189.5t-150.5 -68.5 q-43 0 -84 18.5t-80.5 41t-76 41t-70.5 18.5q-50 0 -75.5 -30t-39.5 -91h-98z" /> +<glyph unicode="&#xd2;" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q315 0 492 -200t177 -552q0 -351 -177.5 -552t-493.5 -201q-323 0 -498.5 197.5t-175.5 557.5zM305 733q0 -297 126.5 -450.5t367.5 -153.5q243 0 367 153t124 451q0 295 -123.5 447.5t-365.5 152.5q-243 0 -369.5 -153.5 t-126.5 -446.5zM514 1886v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="&#xd3;" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q315 0 492 -200t177 -552q0 -351 -177.5 -552t-493.5 -201q-323 0 -498.5 197.5t-175.5 557.5zM305 733q0 -297 126.5 -450.5t367.5 -153.5q243 0 367 153t124 451q0 295 -123.5 447.5t-365.5 152.5q-243 0 -369.5 -153.5 t-126.5 -446.5zM659 1579v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="&#xd4;" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q315 0 492 -200t177 -552q0 -351 -177.5 -552t-493.5 -201q-323 0 -498.5 197.5t-175.5 557.5zM305 733q0 -297 126.5 -450.5t367.5 -153.5q243 0 367 153t124 451q0 295 -123.5 447.5t-365.5 152.5q-243 0 -369.5 -153.5 t-126.5 -446.5zM448 1579v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115z" /> +<glyph unicode="&#xd5;" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q315 0 492 -200t177 -552q0 -351 -177.5 -552t-493.5 -201q-323 0 -498.5 197.5t-175.5 557.5zM305 733q0 -297 126.5 -450.5t367.5 -153.5q243 0 367 153t124 451q0 295 -123.5 447.5t-365.5 152.5q-243 0 -369.5 -153.5 t-126.5 -446.5zM418 1579q13 121 70.5 189.5t148.5 68.5q46 0 89 -18.5t82 -41t75 -41t68 -18.5q49 0 73 29.5t39 91.5h99q-13 -121 -69.5 -189.5t-150.5 -68.5q-43 0 -84 18.5t-80.5 41t-76 41t-70.5 18.5q-50 0 -75.5 -30t-39.5 -91h-98z" /> +<glyph unicode="&#xd6;" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q315 0 492 -200t177 -552q0 -351 -177.5 -552t-493.5 -201q-323 0 -498.5 197.5t-175.5 557.5zM305 733q0 -297 126.5 -450.5t367.5 -153.5q243 0 367 153t124 451q0 295 -123.5 447.5t-365.5 152.5q-243 0 -369.5 -153.5 t-126.5 -446.5zM522 1731q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM903 1731q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="&#xd7;" d="M133 1075l100 101l353 -355l354 355l96 -99l-352 -354l350 -352l-96 -99l-354 351l-348 -351l-101 99l350 352z" /> +<glyph unicode="&#xd8;" horiz-adv-x="1595" d="M125 735q0 357 176 553.5t500 196.5q209 0 366 -94l97 135l120 -80l-106 -148q192 -202 192 -565q0 -351 -177.5 -552t-493.5 -201q-235 0 -383 100l-101 -141l-120 79l108 154q-178 198 -178 563zM305 733q0 -262 101 -416l669 943q-106 73 -274 73 q-243 0 -369.5 -153.5t-126.5 -446.5zM508 211q115 -82 291 -82q243 0 367 153t124 451q0 272 -110 426z" /> +<glyph unicode="&#xd9;" horiz-adv-x="1491" d="M186 520v942h170v-954q0 -183 100 -281t294 -98q185 0 285 98.5t100 282.5v952h170v-946q0 -250 -151 -393t-415 -143t-408.5 144t-144.5 396zM463 1886v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="&#xda;" horiz-adv-x="1491" d="M186 520v942h170v-954q0 -183 100 -281t294 -98q185 0 285 98.5t100 282.5v952h170v-946q0 -250 -151 -393t-415 -143t-408.5 144t-144.5 396zM600 1579v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="&#xdb;" horiz-adv-x="1491" d="M186 520v942h170v-954q0 -183 100 -281t294 -98q185 0 285 98.5t100 282.5v952h170v-946q0 -250 -151 -393t-415 -143t-408.5 144t-144.5 396zM393 1579v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186 h-115z" /> +<glyph unicode="&#xdc;" horiz-adv-x="1491" d="M186 520v942h170v-954q0 -183 100 -281t294 -98q185 0 285 98.5t100 282.5v952h170v-946q0 -250 -151 -393t-415 -143t-408.5 144t-144.5 396zM461 1731q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5z M842 1731q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="&#xdd;" horiz-adv-x="1147" d="M0 1462h186l387 -731l390 731h184l-488 -895v-567h-172v559zM442 1579v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="&#xde;" horiz-adv-x="1251" d="M201 0v1462h170v-256h215q281 0 420 -103.5t139 -318.5q0 -227 -151.5 -346t-438.5 -119h-184v-319h-170zM371 465h168q226 0 327 71.5t101 235.5q0 149 -95 218t-297 69h-204v-594z" /> +<glyph unicode="&#xdf;" horiz-adv-x="1274" d="M176 0v1202q0 178 110 271.5t332 93.5q206 0 318.5 -78.5t112.5 -222.5q0 -135 -143 -250q-88 -70 -116 -103.5t-28 -66.5q0 -32 13.5 -53t49 -49.5t113.5 -79.5q140 -95 191 -173.5t51 -179.5q0 -160 -97 -245.5t-276 -85.5q-188 0 -295 69v154q63 -39 141 -62.5 t150 -23.5q215 0 215 182q0 75 -41.5 128.5t-151.5 123.5q-127 82 -175 143.5t-48 145.5q0 63 34.5 116t105.5 106q75 57 107 102t32 98q0 80 -68 122.5t-195 42.5q-276 0 -276 -223v-1204h-166z" /> +<glyph unicode="&#xe0;" horiz-adv-x="1139" d="M94 303q0 332 531 348l186 6v68q0 129 -55.5 190.5t-177.5 61.5q-137 0 -310 -84l-51 127q81 44 177.5 69t193.5 25q196 0 290.5 -87t94.5 -279v-748h-123l-33 156h-8q-82 -103 -163.5 -139.5t-203.5 -36.5q-163 0 -255.5 84t-92.5 239zM268 301q0 -90 54.5 -137 t152.5 -47q155 0 243.5 85t88.5 238v99l-166 -7q-198 -7 -285.5 -61.5t-87.5 -169.5zM279 1548v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="&#xe1;" horiz-adv-x="1139" d="M94 303q0 332 531 348l186 6v68q0 129 -55.5 190.5t-177.5 61.5q-137 0 -310 -84l-51 127q81 44 177.5 69t193.5 25q196 0 290.5 -87t94.5 -279v-748h-123l-33 156h-8q-82 -103 -163.5 -139.5t-203.5 -36.5q-163 0 -255.5 84t-92.5 239zM268 301q0 -90 54.5 -137 t152.5 -47q155 0 243.5 85t88.5 238v99l-166 -7q-198 -7 -285.5 -61.5t-87.5 -169.5zM436 1241v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="&#xe2;" horiz-adv-x="1139" d="M94 303q0 332 531 348l186 6v68q0 129 -55.5 190.5t-177.5 61.5q-137 0 -310 -84l-51 127q81 44 177.5 69t193.5 25q196 0 290.5 -87t94.5 -279v-748h-123l-33 156h-8q-82 -103 -163.5 -139.5t-203.5 -36.5q-163 0 -255.5 84t-92.5 239zM268 301q0 -90 54.5 -137 t152.5 -47q155 0 243.5 85t88.5 238v99l-166 -7q-198 -7 -285.5 -61.5t-87.5 -169.5zM228 1241v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115z" /> +<glyph unicode="&#xe3;" horiz-adv-x="1139" d="M94 303q0 332 531 348l186 6v68q0 129 -55.5 190.5t-177.5 61.5q-137 0 -310 -84l-51 127q81 44 177.5 69t193.5 25q196 0 290.5 -87t94.5 -279v-748h-123l-33 156h-8q-82 -103 -163.5 -139.5t-203.5 -36.5q-163 0 -255.5 84t-92.5 239zM268 301q0 -90 54.5 -137 t152.5 -47q155 0 243.5 85t88.5 238v99l-166 -7q-198 -7 -285.5 -61.5t-87.5 -169.5zM197 1241q13 121 70.5 189.5t148.5 68.5q46 0 89 -18.5t82 -41t75 -41t68 -18.5q49 0 73 29.5t39 91.5h99q-13 -121 -69.5 -189.5t-150.5 -68.5q-43 0 -84 18.5t-80.5 41t-76 41 t-70.5 18.5q-50 0 -75.5 -30t-39.5 -91h-98z" /> +<glyph unicode="&#xe4;" horiz-adv-x="1139" d="M94 303q0 332 531 348l186 6v68q0 129 -55.5 190.5t-177.5 61.5q-137 0 -310 -84l-51 127q81 44 177.5 69t193.5 25q196 0 290.5 -87t94.5 -279v-748h-123l-33 156h-8q-82 -103 -163.5 -139.5t-203.5 -36.5q-163 0 -255.5 84t-92.5 239zM268 301q0 -90 54.5 -137 t152.5 -47q155 0 243.5 85t88.5 238v99l-166 -7q-198 -7 -285.5 -61.5t-87.5 -169.5zM279 1393q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM660 1393q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75 q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="&#xe5;" horiz-adv-x="1139" d="M94 303q0 332 531 348l186 6v68q0 129 -55.5 190.5t-177.5 61.5q-137 0 -310 -84l-51 127q81 44 177.5 69t193.5 25q196 0 290.5 -87t94.5 -279v-748h-123l-33 156h-8q-82 -103 -163.5 -139.5t-203.5 -36.5q-163 0 -255.5 84t-92.5 239zM268 301q0 -90 54.5 -137 t152.5 -47q155 0 243.5 85t88.5 238v99l-166 -7q-198 -7 -285.5 -61.5t-87.5 -169.5zM358 1456q0 98 60.5 155.5t160.5 57.5q101 0 163 -59.5t62 -151.5q0 -98 -61.5 -157.5t-163.5 -59.5q-101 0 -161 58.5t-60 156.5zM462 1456q0 -56 30 -86.5t87 -30.5q52 0 84.5 30.5 t32.5 86.5t-33 86.5t-84 30.5t-84 -30.5t-33 -86.5z" /> +<glyph unicode="&#xe6;" horiz-adv-x="1757" d="M94 303q0 161 124 250.5t378 97.5l184 6v68q0 129 -58 190.5t-177 61.5q-144 0 -307 -84l-52 127q74 41 173.5 67.5t197.5 26.5q130 0 212.5 -43.5t123.5 -138.5q53 88 138.5 136t195.5 48q192 0 308 -133.5t116 -355.5v-107h-701q8 -395 322 -395q91 0 169.5 17.5 t162.5 56.5v-148q-86 -38 -160.5 -54.5t-175.5 -16.5q-289 0 -414 233q-81 -127 -179.5 -180t-232.5 -53q-163 0 -255.5 85t-92.5 238zM268 301q0 -95 53.5 -139.5t141.5 -44.5q145 0 229 84.5t84 238.5v99l-158 -7q-186 -8 -268 -62.5t-82 -168.5zM954 653h519 q0 156 -64 240t-184 84q-121 0 -190.5 -83t-80.5 -241z" /> +<glyph unicode="&#xe7;" horiz-adv-x="975" d="M115 541q0 275 132.5 425t377.5 150q79 0 158 -17t124 -40l-51 -141q-55 22 -120 36.5t-115 14.5q-334 0 -334 -426q0 -202 81.5 -310t241.5 -108q137 0 281 59v-147q-110 -57 -277 -57q-238 0 -368.5 146.5t-130.5 414.5zM363 -377q45 -8 104 -8q79 0 119.5 20t40.5 74 q0 43 -39.5 69.5t-148.5 43.5l88 178h110l-55 -115q180 -39 180 -174q0 -97 -76.5 -150t-226.5 -53q-51 0 -96 9v106z" /> +<glyph unicode="&#xe8;" horiz-adv-x="1149" d="M115 539q0 265 130.5 421t350.5 156q206 0 326 -135.5t120 -357.5v-105h-755q5 -193 97.5 -293t260.5 -100q177 0 350 74v-148q-88 -38 -166.5 -54.5t-189.5 -16.5q-243 0 -383.5 148t-140.5 411zM291 653h573q0 157 -70 240.5t-200 83.5q-132 0 -210.5 -86t-92.5 -238z M318 1548v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="&#xe9;" horiz-adv-x="1149" d="M115 539q0 265 130.5 421t350.5 156q206 0 326 -135.5t120 -357.5v-105h-755q5 -193 97.5 -293t260.5 -100q177 0 350 74v-148q-88 -38 -166.5 -54.5t-189.5 -16.5q-243 0 -383.5 148t-140.5 411zM291 653h573q0 157 -70 240.5t-200 83.5q-132 0 -210.5 -86t-92.5 -238z M471 1241v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="&#xea;" horiz-adv-x="1149" d="M115 539q0 265 130.5 421t350.5 156q206 0 326 -135.5t120 -357.5v-105h-755q5 -193 97.5 -293t260.5 -100q177 0 350 74v-148q-88 -38 -166.5 -54.5t-189.5 -16.5q-243 0 -383.5 148t-140.5 411zM291 653h573q0 157 -70 240.5t-200 83.5q-132 0 -210.5 -86t-92.5 -238z M259 1241v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115z" /> +<glyph unicode="&#xeb;" horiz-adv-x="1149" d="M115 539q0 265 130.5 421t350.5 156q206 0 326 -135.5t120 -357.5v-105h-755q5 -193 97.5 -293t260.5 -100q177 0 350 74v-148q-88 -38 -166.5 -54.5t-189.5 -16.5q-243 0 -383.5 148t-140.5 411zM291 653h573q0 157 -70 240.5t-200 83.5q-132 0 -210.5 -86t-92.5 -238z M319 1393q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM700 1393q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="&#xec;" horiz-adv-x="518" d="M176 0v1096h166v-1096h-166zM-38 1548v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="&#xed;" horiz-adv-x="518" d="M176 0v1096h166v-1096h-166zM169 1241v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="&#xee;" horiz-adv-x="518" d="M176 0v1096h166v-1096h-166zM-77 1241v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115z" /> +<glyph unicode="&#xef;" horiz-adv-x="518" d="M176 0v1096h166v-1096h-166zM-20 1393q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM361 1393q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="&#xf0;" horiz-adv-x="1221" d="M113 475q0 230 131.5 361t351.5 131q226 0 326 -121l8 4q-57 214 -262 405l-271 -155l-73 108l233 133q-92 62 -186 111l69 117q156 -73 258 -148l238 138l76 -107l-207 -119q152 -143 234.5 -342t82.5 -428q0 -281 -130.5 -432t-377.5 -151q-222 0 -361.5 134.5 t-139.5 360.5zM281 469q0 -167 87.5 -258.5t249.5 -91.5q175 0 255.5 100.5t80.5 292.5q0 147 -90 232t-246 85q-337 0 -337 -360z" /> +<glyph unicode="&#xf1;" horiz-adv-x="1257" d="M176 0v1096h135l27 -150h8q51 81 143 125.5t205 44.5q198 0 298 -95.5t100 -305.5v-715h-166v709q0 134 -61 200t-191 66q-172 0 -252 -93t-80 -307v-575h-166zM278 1241q13 121 70.5 189.5t148.5 68.5q46 0 89 -18.5t82 -41t75 -41t68 -18.5q49 0 73 29.5t39 91.5h99 q-13 -121 -69.5 -189.5t-150.5 -68.5q-43 0 -84 18.5t-80.5 41t-76 41t-70.5 18.5q-50 0 -75.5 -30t-39.5 -91h-98z" /> +<glyph unicode="&#xf2;" horiz-adv-x="1237" d="M115 549q0 268 134 417.5t372 149.5q230 0 365.5 -153t135.5 -414q0 -268 -135 -418.5t-373 -150.5q-147 0 -261 69t-176 198t-62 302zM287 549q0 -210 84 -320t247 -110t247.5 109.5t84.5 320.5q0 209 -84.5 317.5t-249.5 108.5q-163 0 -246 -107t-83 -319zM349 1548v21 h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="&#xf3;" horiz-adv-x="1237" d="M115 549q0 268 134 417.5t372 149.5q230 0 365.5 -153t135.5 -414q0 -268 -135 -418.5t-373 -150.5q-147 0 -261 69t-176 198t-62 302zM287 549q0 -210 84 -320t247 -110t247.5 109.5t84.5 320.5q0 209 -84.5 317.5t-249.5 108.5q-163 0 -246 -107t-83 -319zM479 1241v25 q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="&#xf4;" horiz-adv-x="1237" d="M115 549q0 268 134 417.5t372 149.5q230 0 365.5 -153t135.5 -414q0 -268 -135 -418.5t-373 -150.5q-147 0 -261 69t-176 198t-62 302zM287 549q0 -210 84 -320t247 -110t247.5 109.5t84.5 320.5q0 209 -84.5 317.5t-249.5 108.5q-163 0 -246 -107t-83 -319zM282 1241v23 q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115z" /> +<glyph unicode="&#xf5;" horiz-adv-x="1237" d="M115 549q0 268 134 417.5t372 149.5q230 0 365.5 -153t135.5 -414q0 -268 -135 -418.5t-373 -150.5q-147 0 -261 69t-176 198t-62 302zM287 549q0 -210 84 -320t247 -110t247.5 109.5t84.5 320.5q0 209 -84.5 317.5t-249.5 108.5q-163 0 -246 -107t-83 -319zM249 1241 q13 121 70.5 189.5t148.5 68.5q46 0 89 -18.5t82 -41t75 -41t68 -18.5q49 0 73 29.5t39 91.5h99q-13 -121 -69.5 -189.5t-150.5 -68.5q-43 0 -84 18.5t-80.5 41t-76 41t-70.5 18.5q-50 0 -75.5 -30t-39.5 -91h-98z" /> +<glyph unicode="&#xf6;" horiz-adv-x="1237" d="M115 549q0 268 134 417.5t372 149.5q230 0 365.5 -153t135.5 -414q0 -268 -135 -418.5t-373 -150.5q-147 0 -261 69t-176 198t-62 302zM287 549q0 -210 84 -320t247 -110t247.5 109.5t84.5 320.5q0 209 -84.5 317.5t-249.5 108.5q-163 0 -246 -107t-83 -319zM336 1393 q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM717 1393q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="&#xf7;" d="M104 653v138h961v-138h-961zM471 373q0 60 29.5 90.5t83.5 30.5q52 0 81 -31.5t29 -89.5q0 -57 -29.5 -89t-80.5 -32q-52 0 -82.5 31.5t-30.5 89.5zM471 1071q0 60 29.5 90.5t83.5 30.5q52 0 81 -31.5t29 -89.5q0 -57 -29.5 -89t-80.5 -32q-52 0 -82.5 31.5t-30.5 89.5z " /> +<glyph unicode="&#xf8;" horiz-adv-x="1237" d="M115 549q0 268 134 417.5t372 149.5q154 0 270 -76l84 119l117 -76l-97 -133q127 -152 127 -401q0 -268 -135 -418.5t-373 -150.5q-154 0 -266 69l-84 -117l-114 78l94 131q-129 152 -129 408zM287 549q0 -171 53 -273l465 646q-75 53 -189 53q-163 0 -246 -107t-83 -319 zM434 170q71 -51 184 -51q163 0 247.5 109.5t84.5 320.5q0 164 -51 264z" /> +<glyph unicode="&#xf9;" horiz-adv-x="1257" d="M164 379v717h168v-711q0 -134 61 -200t191 -66q172 0 251.5 94t79.5 307v576h166v-1096h-137l-24 147h-9q-51 -81 -141.5 -124t-206.5 -43q-200 0 -299.5 95t-99.5 304zM333 1548v21h203q32 -69 89 -159.5t101 -143.5v-25h-110q-65 52 -154 148t-129 159z" /> +<glyph unicode="&#xfa;" horiz-adv-x="1257" d="M164 379v717h168v-711q0 -134 61 -200t191 -66q172 0 251.5 94t79.5 307v576h166v-1096h-137l-24 147h-9q-51 -81 -141.5 -124t-206.5 -43q-200 0 -299.5 95t-99.5 304zM506 1241v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111z" /> +<glyph unicode="&#xfb;" horiz-adv-x="1257" d="M164 379v717h168v-711q0 -134 61 -200t191 -66q172 0 251.5 94t79.5 307v576h166v-1096h-137l-24 147h-9q-51 -81 -141.5 -124t-206.5 -43q-200 0 -299.5 95t-99.5 304zM286 1241v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119 q-88 55 -221 186q-136 -134 -219 -186h-115z" /> +<glyph unicode="&#xfc;" horiz-adv-x="1257" d="M164 379v717h168v-711q0 -134 61 -200t191 -66q172 0 251.5 94t79.5 307v576h166v-1096h-137l-24 147h-9q-51 -81 -141.5 -124t-206.5 -43q-200 0 -299.5 95t-99.5 304zM342 1393q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5 q-37 0 -63.5 24.5t-26.5 74.5zM723 1393q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="&#xfd;" horiz-adv-x="1032" d="M2 1096h178l240 -625q79 -214 98 -309h8q13 51 54.5 174.5t271.5 759.5h178l-471 -1248q-70 -185 -163.5 -262.5t-229.5 -77.5q-76 0 -150 17v133q55 -12 123 -12q171 0 244 192l61 156zM411 1241v25q48 62 103.5 150t87.5 153h202v-21q-44 -65 -131 -160t-151 -147h-111 z" /> +<glyph unicode="&#xfe;" horiz-adv-x="1255" d="M176 -492v2048h166v-466q0 -52 -6 -142h8q66 89 151 128.5t191 39.5q215 0 335 -150t120 -417q0 -268 -120.5 -418.5t-334.5 -150.5q-222 0 -344 161h-12l4 -34q8 -77 8 -140v-459h-166zM342 549q0 -231 77 -330.5t247 -99.5q303 0 303 432q0 215 -74 319.5t-231 104.5 q-168 0 -244 -92t-78 -293v-41z" /> +<glyph unicode="&#xff;" horiz-adv-x="1032" d="M2 1096h178l240 -625q79 -214 98 -309h8q13 51 54.5 174.5t271.5 759.5h178l-471 -1248q-70 -185 -163.5 -262.5t-229.5 -77.5q-76 0 -150 17v133q55 -12 123 -12q171 0 244 192l61 156zM234 1393q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5 t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM615 1393q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="&#x131;" horiz-adv-x="518" d="M176 0v1096h166v-1096h-166z" /> +<glyph unicode="&#x152;" horiz-adv-x="1890" d="M125 735q0 360 174 555t494 195q102 0 192 -23h782v-151h-589v-471h551v-150h-551v-538h589v-152h-768q-102 -20 -194 -20q-327 0 -503.5 196.5t-176.5 558.5zM305 733q0 -297 128.5 -450.5t375.5 -153.5q112 0 199 33v1141q-87 30 -197 30q-249 0 -377.5 -152.5 t-128.5 -447.5z" /> +<glyph unicode="&#x153;" horiz-adv-x="1929" d="M113 549q0 265 131 415t366 150q131 0 233.5 -59.5t164.5 -173.5q58 112 154 172.5t222 60.5q201 0 320 -132.5t119 -358.5v-105h-729q8 -393 338 -393q94 0 174.5 17.5t167.5 56.5v-148q-88 -39 -164 -55t-180 -16q-293 0 -418 235q-62 -116 -166.5 -175.5t-241.5 -59.5 q-223 0 -357 152.5t-134 416.5zM287 549q0 -211 76 -320.5t243 -109.5q163 0 239.5 106.5t76.5 315.5q0 221 -77.5 327.5t-242.5 106.5q-166 0 -240.5 -108t-74.5 -318zM1098 653h544q0 158 -66 240t-194 82q-127 0 -199.5 -82t-84.5 -240z" /> +<glyph unicode="&#x178;" horiz-adv-x="1147" d="M0 1462h186l387 -731l390 731h184l-488 -895v-567h-172v559zM294 1731q0 52 26.5 75t63.5 23q38 0 65.5 -23t27.5 -75q0 -50 -27.5 -74.5t-65.5 -24.5q-37 0 -63.5 24.5t-26.5 74.5zM675 1731q0 52 26.5 75t63.5 23t64.5 -23t27.5 -75q0 -50 -27.5 -74.5t-64.5 -24.5 t-63.5 24.5t-26.5 74.5z" /> +<glyph unicode="&#x2c6;" horiz-adv-x="1212" d="M268 1241v23q127 136 178 200t74 105h166q22 -42 76.5 -108.5t179.5 -196.5v-23h-119q-88 55 -221 186q-136 -134 -219 -186h-115z" /> +<glyph unicode="&#x2da;" horiz-adv-x="1182" d="M367 1456q0 98 60.5 155.5t160.5 57.5q101 0 163 -59.5t62 -151.5q0 -98 -61.5 -157.5t-163.5 -59.5q-101 0 -161 58.5t-60 156.5zM471 1456q0 -56 30 -86.5t87 -30.5q52 0 84.5 30.5t32.5 86.5t-33 86.5t-84 30.5t-84 -30.5t-33 -86.5z" /> +<glyph unicode="&#x2dc;" horiz-adv-x="1212" d="M264 1241q13 121 70.5 189.5t148.5 68.5q46 0 89 -18.5t82 -41t75 -41t68 -18.5q49 0 73 29.5t39 91.5h99q-13 -121 -69.5 -189.5t-150.5 -68.5q-43 0 -84 18.5t-80.5 41t-76 41t-70.5 18.5q-50 0 -75.5 -30t-39.5 -91h-98z" /> +<glyph unicode="&#x2000;" horiz-adv-x="953" /> +<glyph unicode="&#x2001;" horiz-adv-x="1907" /> +<glyph unicode="&#x2002;" horiz-adv-x="953" /> +<glyph unicode="&#x2003;" horiz-adv-x="1907" /> +<glyph unicode="&#x2004;" horiz-adv-x="635" /> +<glyph unicode="&#x2005;" horiz-adv-x="476" /> +<glyph unicode="&#x2006;" horiz-adv-x="317" /> +<glyph unicode="&#x2007;" horiz-adv-x="317" /> +<glyph unicode="&#x2008;" horiz-adv-x="238" /> +<glyph unicode="&#x2009;" horiz-adv-x="381" /> +<glyph unicode="&#x200a;" horiz-adv-x="105" /> +<glyph unicode="&#x2010;" horiz-adv-x="659" d="M84 473v152h491v-152h-491z" /> +<glyph unicode="&#x2011;" horiz-adv-x="659" d="M84 473v152h491v-152h-491z" /> +<glyph unicode="&#x2012;" horiz-adv-x="659" d="M84 473v152h491v-152h-491z" /> +<glyph unicode="&#x2013;" horiz-adv-x="1024" d="M82 473v152h860v-152h-860z" /> +<glyph unicode="&#x2014;" horiz-adv-x="2048" d="M82 473v152h1884v-152h-1884z" /> +<glyph unicode="&#x2018;" horiz-adv-x="348" d="M25 983q22 90 71 224t105 255h123q-66 -254 -103 -501h-184z" /> +<glyph unicode="&#x2019;" horiz-adv-x="348" d="M25 961q70 285 102 501h182l15 -22q-26 -100 -75 -232.5t-102 -246.5h-122z" /> +<glyph unicode="&#x201a;" horiz-adv-x="502" d="M63 -264q27 104 59.5 257t45.5 245h182l15 -23q-26 -100 -75 -232.5t-102 -246.5h-125z" /> +<glyph unicode="&#x201c;" horiz-adv-x="717" d="M25 983q22 90 71 224t105 255h123q-66 -254 -103 -501h-184zM391 983q56 215 178 479h123q-30 -115 -59.5 -259.5t-42.5 -241.5h-184z" /> +<glyph unicode="&#x201d;" horiz-adv-x="717" d="M25 961q70 285 102 501h182l15 -22q-26 -100 -75 -232.5t-102 -246.5h-122zM391 961q26 100 59 254t46 247h182l14 -22q-24 -91 -72 -224t-104 -255h-125z" /> +<glyph unicode="&#x201e;" horiz-adv-x="829" d="M25 -263q70 285 102 501h182l15 -22q-26 -100 -75 -232.5t-102 -246.5h-122zM391 -263q26 100 59 254t46 247h182l14 -22q-24 -91 -72 -224t-104 -255h-125z" /> +<glyph unicode="&#x2022;" horiz-adv-x="770" d="M164 748q0 121 56.5 184t164.5 63q105 0 163 -62t58 -185q0 -119 -57.5 -183.5t-163.5 -64.5q-107 0 -164 65.5t-57 182.5z" /> +<glyph unicode="&#x2026;" horiz-adv-x="1606" d="M152 106q0 67 30.5 101.5t87.5 34.5q58 0 90.5 -34.5t32.5 -101.5q0 -65 -33 -100t-90 -35q-51 0 -84.5 31.5t-33.5 103.5zM682 106q0 67 30.5 101.5t87.5 34.5q58 0 90.5 -34.5t32.5 -101.5q0 -65 -33 -100t-90 -35q-51 0 -84.5 31.5t-33.5 103.5zM1213 106 q0 67 30.5 101.5t87.5 34.5q58 0 90.5 -34.5t32.5 -101.5q0 -65 -33 -100t-90 -35q-51 0 -84.5 31.5t-33.5 103.5z" /> +<glyph unicode="&#x202f;" horiz-adv-x="381" /> +<glyph unicode="&#x2039;" horiz-adv-x="623" d="M82 524v27l342 407l119 -69l-289 -350l289 -351l-119 -71z" /> +<glyph unicode="&#x203a;" horiz-adv-x="623" d="M80 188l287 351l-287 350l117 69l344 -407v-27l-344 -407z" /> +<glyph unicode="&#x2044;" horiz-adv-x="266" d="M-391 0l903 1462h143l-903 -1462h-143z" /> +<glyph unicode="&#x205f;" horiz-adv-x="476" /> +<glyph unicode="&#x2074;" horiz-adv-x="711" d="M20 788v101l408 579h139v-563h125v-117h-125v-202h-145v202h-402zM160 905h262v195q0 134 6 209q-5 -12 -17 -31.5t-27 -41.5l-30 -46q-15 -22 -26 -39z" /> +<glyph unicode="&#x20ac;" horiz-adv-x="1208" d="M63 506v129h152l-2 42v44l2 80h-152v129h164q39 261 185 407t383 146q201 0 366 -97l-71 -139q-166 86 -295 86q-319 0 -398 -403h510v-129h-524l-2 -57v-64l2 -45h463v-129h-447q37 -180 138.5 -278.5t271.5 -98.5q156 0 309 66v-150q-146 -65 -317 -65 q-237 0 -381.5 134.5t-190.5 391.5h-166z" /> +<glyph unicode="&#x2122;" horiz-adv-x="1589" d="M37 1356v106h543v-106h-211v-615h-123v615h-209zM647 741v721h187l196 -559l203 559h180v-721h-127v420l6 137h-8l-211 -557h-104l-201 559h-8l6 -129v-430h-119z" /> +<glyph unicode="&#x2212;" d="M104 653v138h961v-138h-961z" /> +<glyph unicode="&#xe000;" horiz-adv-x="1095" d="M0 1095h1095v-1095h-1095v1095z" /> +<glyph unicode="&#xfb01;" horiz-adv-x="1212" d="M29 967v75l196 60v61q0 404 353 404q87 0 204 -35l-43 -133q-96 31 -164 31q-94 0 -139 -62.5t-45 -200.5v-71h279v-129h-279v-967h-166v967h-196zM856 1393q0 57 28 83.5t70 26.5q40 0 69 -27t29 -83t-29 -83.5t-69 -27.5q-42 0 -70 27.5t-28 83.5zM870 0v1096h166 v-1096h-166z" /> +<glyph unicode="&#xfb02;" horiz-adv-x="1212" d="M29 967v75l196 60v61q0 404 353 404q87 0 204 -35l-43 -133q-96 31 -164 31q-94 0 -139 -62.5t-45 -200.5v-71h279v-129h-279v-967h-166v967h-196zM870 0v1556h166v-1556h-166z" /> +<glyph unicode="&#xfb03;" horiz-adv-x="1909" d="M717 967v75l196 60v61q0 404 353 404q87 0 204 -35l-43 -133q-96 31 -164 31q-94 0 -139 -62.5t-45 -200.5v-71h279v-129h-279v-967h-166v967h-196zM29 967v75l196 60v61q0 404 353 404q87 0 204 -35l-43 -133q-96 31 -164 31q-94 0 -139 -62.5t-45 -200.5v-71h279v-129 h-279v-967h-166v967h-196zM1551 1393q0 57 28 83.5t70 26.5q40 0 69 -27t29 -83t-29 -83.5t-69 -27.5q-42 0 -70 27.5t-28 83.5zM1565 0v1096h166v-1096h-166z" /> +<glyph unicode="&#xfb04;" horiz-adv-x="1909" d="M717 967v75l196 60v61q0 404 353 404q87 0 204 -35l-43 -133q-96 31 -164 31q-94 0 -139 -62.5t-45 -200.5v-71h279v-129h-279v-967h-166v967h-196zM29 967v75l196 60v61q0 404 353 404q87 0 204 -35l-43 -133q-96 31 -164 31q-94 0 -139 -62.5t-45 -200.5v-71h279v-129 h-279v-967h-166v967h-196zM1565 0v1556h166v-1556h-166z" /> +</font> +</defs></svg> +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Regular-webfont.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.svg b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.svg @@ -0,0 +1,251 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata> +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 2011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom +</metadata> +<defs> +<font id="OpenSansSemibold" horiz-adv-x="1169" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="&#x09;" horiz-adv-x="532" /> +<glyph unicode="&#xa0;" horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="565" d="M133 125q0 74 39 112.5t111 38.5q71 0 109 -40t38 -111t-38.5 -112.5t-108.5 -41.5q-71 0 -110.5 40t-39.5 114zM145 1462h277l-51 -1018h-174z" /> +<glyph unicode="&#x22;" horiz-adv-x="893" d="M133 1462h232l-41 -528h-150zM528 1462h232l-41 -528h-150z" /> +<glyph unicode="#" horiz-adv-x="1323" d="M47 418v168h283l57 284h-264v168h293l80 422h180l-80 -422h252l80 422h174l-80 -422h252v-168h-285l-55 -284h270v-168h-303l-80 -418h-178l80 418h-248l-80 -418h-174l76 418h-250zM506 586h250l57 284h-250z" /> +<glyph unicode="$" d="M111 168v211q86 -42 201 -70.5t206 -29.5v374l-84 31q-164 63 -239.5 150.5t-75.5 216.5q0 138 107.5 227t291.5 108v168h133v-165q203 -7 385 -82l-73 -183q-157 62 -312 74v-364l76 -29q190 -73 263 -154t73 -198q0 -145 -106 -239t-306 -116v-217h-133v211 q-248 4 -407 76zM354 1053q0 -57 35.5 -95t128.5 -75v311q-80 -12 -122 -49t-42 -92zM651 287q176 27 176 151q0 58 -40.5 95.5t-135.5 72.5v-319z" /> +<glyph unicode="%" horiz-adv-x="1765" d="M84 1026q0 457 319 457q157 0 241.5 -118.5t84.5 -338.5q0 -230 -82.5 -345.5t-243.5 -115.5q-152 0 -235.5 119.5t-83.5 341.5zM279 1024q0 -149 29 -222t95 -73q132 0 132 295t-132 295q-66 0 -95 -73t-29 -222zM379 0l811 1462h194l-811 -1462h-194zM1036 440 q0 457 320 457q154 0 239.5 -118t85.5 -339q0 -230 -83 -345t-242 -115q-152 0 -236 118.5t-84 341.5zM1231 440q0 -149 29.5 -223t95.5 -74q131 0 131 297q0 293 -131 293q-66 0 -95.5 -72t-29.5 -221z" /> +<glyph unicode="&#x26;" horiz-adv-x="1516" d="M96 387q0 131 64 228.5t231 193.5q-95 111 -129.5 187.5t-34.5 158.5q0 152 108.5 240t291.5 88q177 0 278 -85.5t101 -230.5q0 -114 -67.5 -207t-225.5 -186l346 -334q81 107 135 314h242q-70 -284 -224 -463l301 -291h-303l-149 145q-102 -82 -217.5 -123.5 t-255.5 -41.5q-230 0 -361 109t-131 298zM344 403q0 -98 69.5 -159.5t186.5 -61.5q183 0 313 107l-383 377q-106 -68 -146 -127.5t-40 -135.5zM451 1147q0 -63 33.5 -119t93.5 -119q113 64 158.5 119.5t45.5 124.5q0 65 -43.5 104t-115.5 39q-79 0 -125.5 -40.5 t-46.5 -108.5z" /> +<glyph unicode="'" horiz-adv-x="498" d="M133 1462h232l-41 -528h-150z" /> +<glyph unicode="(" horiz-adv-x="649" d="M82 561q0 265 77.5 496t223.5 405h205q-139 -188 -213 -421.5t-74 -477.5t74 -473t211 -414h-203q-147 170 -224 397t-77 488z" /> +<glyph unicode=")" horiz-adv-x="649" d="M61 1462h205q147 -175 224 -406.5t77 -494.5t-77.5 -490t-223.5 -395h-203q138 187 211.5 415t73.5 472q0 245 -74 477.5t-213 421.5z" /> +<glyph unicode="*" horiz-adv-x="1122" d="M74 1065l35 217l376 -108l-41 382h228l-41 -382l385 108l28 -217l-360 -29l236 -311l-199 -107l-166 338l-149 -338l-205 107l231 311z" /> +<glyph unicode="+" d="M96 633v178h398v408h180v-408h399v-178h-399v-406h-180v406h-398z" /> +<glyph unicode="," horiz-adv-x="547" d="M63 -264q69 270 103 502h231l15 -23q-48 -186 -176 -479h-173z" /> +<glyph unicode="-" horiz-adv-x="659" d="M72 449v200h514v-200h-514z" /> +<glyph unicode="." horiz-adv-x="563" d="M133 125q0 73 38 112t110 39q73 0 111 -40.5t38 -110.5q0 -71 -38.5 -112.5t-110.5 -41.5t-110 41t-38 113z" /> +<glyph unicode="/" horiz-adv-x="799" d="M16 0l545 1462h221l-544 -1462h-222z" /> +<glyph unicode="0" d="M88 731q0 387 122.5 570.5t373.5 183.5q245 0 371 -192t126 -562q0 -381 -122.5 -566t-374.5 -185q-244 0 -370 191t-126 560zM326 731q0 -299 61.5 -427t196.5 -128t197.5 130t62.5 425q0 294 -62.5 425.5t-197.5 131.5t-196.5 -129t-61.5 -428z" /> +<glyph unicode="1" d="M154 1124l430 338h196v-1462h-235v944q0 169 8 268q-23 -24 -56.5 -53t-224.5 -184z" /> +<glyph unicode="2" d="M90 0v178l377 379q167 171 221.5 242.5t79.5 134.5t25 135q0 99 -59.5 156t-164.5 57q-84 0 -162.5 -31t-181.5 -112l-127 155q122 103 237 146t245 43q204 0 327 -106.5t123 -286.5q0 -99 -35.5 -188t-109 -183.5t-244.5 -255.5l-254 -246v-10h694v-207h-991z" /> +<glyph unicode="3" d="M86 59v209q93 -46 197 -71t200 -25q170 0 254 63t84 195q0 117 -93 172t-292 55h-127v191h129q350 0 350 242q0 94 -61 145t-180 51q-83 0 -160 -23.5t-182 -91.5l-115 164q201 148 467 148q221 0 345 -95t124 -262q0 -139 -81 -231.5t-228 -124.5v-8q176 -22 264 -109.5 t88 -232.5q0 -211 -149 -325.5t-424 -114.5q-243 0 -410 79z" /> +<glyph unicode="4" d="M39 319v181l668 966h229v-952h197v-195h-197v-319h-229v319h-668zM258 514h449v367q0 196 10 321h-8q-28 -66 -88 -160z" /> +<glyph unicode="5" d="M117 59v213q81 -46 186 -71t195 -25q159 0 242 71t83 208q0 262 -334 262q-47 0 -116 -9.5t-121 -21.5l-105 62l56 714h760v-209h-553l-33 -362q35 6 85.5 14t123.5 8q221 0 350 -117t129 -319q0 -234 -146.5 -365.5t-416.5 -131.5q-245 0 -385 79z" /> +<glyph unicode="6" d="M94 623q0 858 699 858q110 0 186 -17v-196q-76 22 -176 22q-235 0 -353 -126t-128 -404h12q47 81 132 125.5t200 44.5q199 0 310 -122t111 -331q0 -230 -128.5 -363.5t-350.5 -133.5q-157 0 -273 75.5t-178.5 220t-62.5 347.5zM332 508q0 -141 76.5 -237.5t195.5 -96.5 q121 0 186.5 78t65.5 223q0 126 -61.5 198t-184.5 72q-76 0 -140 -32.5t-101 -89t-37 -115.5z" /> +<glyph unicode="7" d="M74 1253v207h1011v-164l-575 -1296h-254l578 1253h-760z" /> +<glyph unicode="8" d="M88 371q0 122 68.5 219.5t224.5 173.5q-134 80 -191 169t-57 200q0 159 125 253.5t326 94.5q208 0 329 -95.5t121 -255.5q0 -225 -270 -358q172 -86 244.5 -181t72.5 -212q0 -181 -133 -290t-360 -109q-238 0 -369 102t-131 289zM313 379q0 -104 73 -161.5t198 -57.5 q129 0 200.5 59.5t71.5 161.5q0 81 -66 148t-200 124l-29 13q-132 -58 -190 -127.5t-58 -159.5zM360 1116q0 -52 22 -93t64 -74.5t142 -80.5q120 53 169.5 111.5t49.5 136.5q0 85 -61.5 134.5t-163.5 49.5q-100 0 -161 -49.5t-61 -134.5z" /> +<glyph unicode="9" d="M86 981q0 229 128.5 364.5t350.5 135.5q156 0 272 -76t179 -220.5t63 -346.5q0 -432 -174 -645t-524 -213q-133 0 -191 16v197q89 -25 179 -25q238 0 355 128t128 402h-12q-59 -90 -142.5 -130t-195.5 -40q-194 0 -305 121t-111 332zM317 983q0 -125 60.5 -196.5 t183.5 -71.5q119 0 200 71t81 166q0 89 -34.5 166.5t-96.5 122.5t-142 45q-122 0 -187 -79.5t-65 -223.5z" /> +<glyph unicode=":" horiz-adv-x="563" d="M133 125q0 73 38 112t110 39q73 0 111 -40.5t38 -110.5q0 -71 -38.5 -112.5t-110.5 -41.5t-110 41t-38 113zM133 979q0 151 148 151q75 0 112 -40t37 -111t-38.5 -112.5t-110.5 -41.5t-110 41t-38 113z" /> +<glyph unicode=";" horiz-adv-x="569" d="M63 -264q69 270 103 502h231l15 -23q-48 -186 -176 -479h-173zM131 979q0 151 148 151q75 0 112 -40t37 -111t-38.5 -112.5t-110.5 -41.5t-110 41t-38 113z" /> +<glyph unicode="&#x3c;" d="M96 651v121l977 488v-195l-733 -344l733 -303v-197z" /> +<glyph unicode="=" d="M102 432v178h963v-178h-963zM102 831v179h963v-179h-963z" /> +<glyph unicode="&#x3e;" d="M96 221v197l733 303l-733 344v195l977 -488v-121z" /> +<glyph unicode="?" horiz-adv-x="928" d="M16 1370q203 113 435 113q196 0 311 -96t115 -265q0 -75 -22 -133.5t-66.5 -111.5t-153.5 -138q-93 -73 -124.5 -121t-31.5 -129v-45h-196v64q0 110 40 183t140 151q119 94 153.5 146t34.5 124q0 84 -56 129t-161 45q-95 0 -176 -27t-158 -65zM242 125q0 151 147 151 q72 0 110 -39.5t38 -111.5q0 -71 -38.5 -112.5t-109.5 -41.5t-109 40.5t-38 113.5z" /> +<glyph unicode="@" horiz-adv-x="1839" d="M111 586q0 261 112 464.5t310.5 311.5t449.5 108q217 0 386.5 -90t263 -256.5t93.5 -384.5q0 -143 -45 -261.5t-126.5 -184.5t-188.5 -66q-79 0 -137 42t-78 114h-12q-49 -78 -121 -117t-162 -39q-163 0 -256.5 105t-93.5 284q0 206 124 334.5t333 128.5 q76 0 168.5 -13.5t164.5 -37.5l-22 -465v-24q0 -160 104 -160q79 0 125.5 102t46.5 260q0 171 -70 300.5t-199 199.5t-296 70q-213 0 -370.5 -88t-240.5 -251.5t-83 -379.5q0 -290 155 -446t445 -156q221 0 461 90v-164q-210 -86 -457 -86q-370 0 -577 199.5t-207 556.5z M698 612q0 -233 183 -233q193 0 211 293l12 239q-63 17 -135 17q-128 0 -199.5 -85t-71.5 -231z" /> +<glyph unicode="A" horiz-adv-x="1354" d="M0 0l547 1468h260l547 -1468h-254l-146 406h-559l-143 -406h-252zM465 612h426l-137 398q-15 40 -41.5 126t-36.5 126q-27 -123 -79 -269z" /> +<glyph unicode="B" horiz-adv-x="1352" d="M193 0v1462h434q302 0 436.5 -88t134.5 -278q0 -128 -66 -213t-190 -107v-10q154 -29 226.5 -114.5t72.5 -231.5q0 -197 -137.5 -308.5t-382.5 -111.5h-528zM432 201h254q150 0 226.5 57.5t76.5 181.5q0 114 -78 169t-237 55h-242v-463zM432 858h230q150 0 219 47.5 t69 161.5q0 103 -74.5 149t-236.5 46h-207v-404z" /> +<glyph unicode="C" horiz-adv-x="1298" d="M121 731q0 228 83.5 399t241.5 262t371 91q224 0 414 -94l-86 -199q-74 35 -156.5 61.5t-173.5 26.5q-206 0 -324 -146t-118 -403q0 -269 113.5 -407t328.5 -138q93 0 180 18.5t181 47.5v-205q-172 -65 -390 -65q-321 0 -493 194.5t-172 556.5z" /> +<glyph unicode="D" horiz-adv-x="1503" d="M193 0v1462h452q349 0 543 -188t194 -529q0 -362 -201 -553.5t-579 -191.5h-409zM432 201h170q528 0 528 536q0 525 -491 525h-207v-1061z" /> +<glyph unicode="E" horiz-adv-x="1143" d="M193 0v1462h827v-202h-588v-398h551v-200h-551v-459h588v-203h-827z" /> +<glyph unicode="F" horiz-adv-x="1090" d="M193 0v1462h825v-202h-588v-457h551v-203h-551v-600h-237z" /> +<glyph unicode="G" horiz-adv-x="1487" d="M121 731q0 353 203 552.5t559 199.5q229 0 434 -88l-84 -199q-178 82 -356 82q-234 0 -370 -147t-136 -402q0 -268 122.5 -407.5t352.5 -139.5q116 0 248 29v377h-303v205h538v-734q-132 -43 -253.5 -61t-262.5 -18q-332 0 -512 196.5t-180 554.5z" /> +<glyph unicode="H" horiz-adv-x="1538" d="M193 0v1462h239v-598h674v598h240v-1462h-240v659h-674v-659h-239z" /> +<glyph unicode="I" horiz-adv-x="625" d="M193 0v1462h239v-1462h-239z" /> +<glyph unicode="J" horiz-adv-x="612" d="M-156 -182q84 -21 146 -21q196 0 196 248v1417h240v-1409q0 -224 -106.5 -342.5t-311.5 -118.5q-98 0 -164 25v201z" /> +<glyph unicode="K" horiz-adv-x="1309" d="M193 0v1462h239v-698q98 120 195 231l395 467h272q-383 -450 -549 -641l564 -821h-277l-459 662l-141 -115v-547h-239z" /> +<glyph unicode="L" horiz-adv-x="1110" d="M193 0v1462h239v-1257h619v-205h-858z" /> +<glyph unicode="M" horiz-adv-x="1890" d="M193 0v1462h337l406 -1163h6l418 1163h338v-1462h-230v723q0 109 5.5 284t9.5 212h-8l-439 -1219h-211l-424 1221h-8q17 -272 17 -510v-711h-217z" /> +<glyph unicode="N" horiz-adv-x="1604" d="M193 0v1462h290l717 -1159h6q-2 23 -8 167.5t-6 225.5v766h219v-1462h-293l-719 1165h-8l5 -65q14 -186 14 -340v-760h-217z" /> +<glyph unicode="O" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q326 0 504 -197t178 -555q0 -357 -178.5 -555t-505.5 -198q-331 0 -508.5 196.5t-177.5 558.5zM375 733q0 -270 109 -409.5t323 -139.5q213 0 321.5 138t108.5 411q0 269 -107.5 408t-320.5 139q-215 0 -324.5 -139t-109.5 -408z" /> +<glyph unicode="P" horiz-adv-x="1260" d="M193 0v1462h421q274 0 410.5 -112t136.5 -330q0 -229 -150 -351t-427 -122h-152v-547h-239zM432 748h127q184 0 270 64t86 200q0 126 -77 188t-240 62h-166v-514z" /> +<glyph unicode="Q" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q326 0 504 -197t178 -555q0 -266 -101.5 -448t-295.5 -256l350 -377h-322l-276 328h-39q-331 0 -508.5 196.5t-177.5 558.5zM375 733q0 -270 109 -409.5t323 -139.5q213 0 321.5 138t108.5 411q0 269 -107.5 408t-320.5 139 q-215 0 -324.5 -139t-109.5 -408z" /> +<glyph unicode="R" horiz-adv-x="1309" d="M193 0v1462h413q283 0 419 -106t136 -320q0 -273 -284 -389l413 -647h-272l-350 584h-236v-584h-239zM432 782h166q167 0 242 62t75 184q0 124 -81 178t-244 54h-158v-478z" /> +<glyph unicode="S" horiz-adv-x="1126" d="M100 57v226q100 -47 212.5 -74t209.5 -27q142 0 209.5 54t67.5 145q0 82 -62 139t-256 135q-200 81 -282 185t-82 250q0 183 130 288t349 105q210 0 418 -92l-76 -195q-195 82 -348 82q-116 0 -176 -50.5t-60 -133.5q0 -57 24 -97.5t79 -76.5t198 -95q161 -67 236 -125 t110 -131t35 -172q0 -195 -141 -306t-389 -111t-406 77z" /> +<glyph unicode="T" horiz-adv-x="1159" d="M29 1257v205h1099v-205h-430v-1257h-239v1257h-430z" /> +<glyph unicode="U" horiz-adv-x="1520" d="M180 520v942h240v-925q0 -181 84 -267t258 -86q338 0 338 355v923h239v-946q0 -162 -69.5 -283.5t-201 -187t-314.5 -65.5q-272 0 -423 144t-151 396z" /> +<glyph unicode="V" horiz-adv-x="1274" d="M0 1462h246l305 -909q24 -65 51 -167.5t35 -152.5q13 76 40 176t44 148l305 905h248l-512 -1462h-252z" /> +<glyph unicode="W" horiz-adv-x="1937" d="M12 1462h244l209 -852q49 -205 70 -362q11 85 33 190t40 170l238 854h237l244 -858q35 -119 74 -356q15 143 72 364l208 850h242l-381 -1462h-260l-248 872q-16 57 -40 164.5t-29 149.5q-10 -64 -32.5 -166t-37.5 -152l-242 -868h-260l-189 732z" /> +<glyph unicode="X" horiz-adv-x="1274" d="M4 0l485 758l-454 704h266l338 -553l338 553h258l-457 -708l492 -754h-275l-366 598l-369 -598h-256z" /> +<glyph unicode="Y" horiz-adv-x="1212" d="M0 1462h260l346 -667l346 667h260l-487 -895v-567h-240v559z" /> +<glyph unicode="Z" horiz-adv-x="1178" d="M66 0v166l737 1091h-717v205h1006v-168l-740 -1089h760v-205h-1046z" /> +<glyph unicode="[" horiz-adv-x="676" d="M154 -324v1786h471v-176h-256v-1433h256v-177h-471z" /> +<glyph unicode="\" horiz-adv-x="799" d="M16 1462h222l544 -1462h-221z" /> +<glyph unicode="]" horiz-adv-x="676" d="M51 -147h256v1433h-256v176h469v-1786h-469v177z" /> +<glyph unicode="^" horiz-adv-x="1100" d="M29 535l436 935h121l485 -935h-194l-349 694l-307 -694h-192z" /> +<glyph unicode="_" horiz-adv-x="879" d="M-4 -184h887v-135h-887v135z" /> +<glyph unicode="`" horiz-adv-x="1212" d="M362 1548v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5z" /> +<glyph unicode="a" horiz-adv-x="1188" d="M90 317q0 171 127 258t387 95l191 6v59q0 106 -49.5 158.5t-153.5 52.5q-85 0 -163 -25t-150 -59l-76 168q90 47 197 71.5t202 24.5q211 0 318.5 -92t107.5 -289v-745h-168l-47 154h-8q-80 -101 -161 -137.5t-208 -36.5q-163 0 -254.5 88t-91.5 249zM334 315 q0 -74 44 -114.5t132 -40.5q128 0 205.5 71.5t77.5 200.5v96l-142 -6q-166 -6 -241.5 -55.5t-75.5 -151.5z" /> +<glyph unicode="b" horiz-adv-x="1276" d="M168 0v1556h235v-370q0 -41 -4 -122t-6 -103h10q112 165 330 165q207 0 322.5 -150t115.5 -421q0 -272 -117 -423.5t-325 -151.5q-210 0 -326 151h-16l-43 -131h-176zM403 555q0 -202 64 -292.5t209 -90.5q125 0 189.5 99t64.5 286q0 377 -258 377q-142 0 -204.5 -83.5 t-64.5 -279.5v-16z" /> +<glyph unicode="c" horiz-adv-x="1014" d="M102 547q0 279 136.5 429t394.5 150q175 0 315 -65l-71 -189q-149 58 -246 58q-287 0 -287 -381q0 -186 71.5 -279.5t209.5 -93.5q157 0 297 78v-205q-63 -37 -134.5 -53t-173.5 -16q-251 0 -381.5 146.5t-130.5 420.5z" /> +<glyph unicode="d" horiz-adv-x="1276" d="M102 551q0 272 117.5 423.5t325.5 151.5q218 0 332 -161h12q-17 119 -17 188v403h236v-1556h-184l-41 145h-11q-113 -165 -331 -165q-207 0 -323 150t-116 421zM344 547q0 -184 65 -280.5t195 -96.5q145 0 211 81.5t68 264.5v33q0 209 -68 297t-213 88 q-124 0 -191 -100.5t-67 -286.5z" /> +<glyph unicode="e" horiz-adv-x="1180" d="M102 545q0 271 135 426t371 155q219 0 346 -133t127 -366v-127h-737q5 -161 87 -247.5t231 -86.5q98 0 182.5 18.5t181.5 61.5v-191q-86 -41 -174 -58t-201 -17q-258 0 -403.5 150.5t-145.5 414.5zM348 670h502q-2 137 -66 207.5t-176 70.5t-179.5 -71t-80.5 -207z" /> +<glyph unicode="f" horiz-adv-x="743" d="M35 928v110l182 72v72q0 196 92 290.5t281 94.5q124 0 244 -41l-62 -178q-87 28 -166 28q-80 0 -116.5 -49.5t-36.5 -148.5v-72h270v-178h-270v-928h-236v928h-182z" /> +<glyph unicode="g" horiz-adv-x="1139" d="M23 -184q0 102 64.5 171.5t180.5 96.5q-47 20 -77.5 64.5t-30.5 93.5q0 62 35 105t104 85q-86 37 -139.5 120.5t-53.5 195.5q0 180 113.5 279t323.5 99q47 0 98.5 -6.5t77.5 -13.5h383v-129l-189 -35q26 -35 43 -86t17 -108q0 -171 -118 -269t-325 -98q-53 0 -96 8 q-76 -47 -76 -110q0 -38 35.5 -57t130.5 -19h193q183 0 278 -78t95 -225q0 -188 -155 -290t-448 -102q-226 0 -345 80t-119 228zM233 -172q0 -76 68.5 -117t192.5 -41q192 0 286 55t94 146q0 72 -51.5 102.5t-191.5 30.5h-178q-101 0 -160.5 -47.5t-59.5 -128.5zM334 748 q0 -104 53.5 -160t153.5 -56q204 0 204 218q0 108 -50.5 166.5t-153.5 58.5q-102 0 -154.5 -58t-52.5 -169z" /> +<glyph unicode="h" horiz-adv-x="1300" d="M168 0v1556h235v-395q0 -95 -12 -203h15q48 80 133.5 124t199.5 44q402 0 402 -405v-721h-236v680q0 128 -51.5 191t-163.5 63q-148 0 -217.5 -88.5t-69.5 -296.5v-549h-235z" /> +<glyph unicode="i" horiz-adv-x="571" d="M154 1399q0 63 34.5 97t98.5 34q62 0 96.5 -34t34.5 -97q0 -60 -34.5 -94.5t-96.5 -34.5q-64 0 -98.5 34.5t-34.5 94.5zM168 0v1106h235v-1106h-235z" /> +<glyph unicode="j" horiz-adv-x="571" d="M-121 -281q68 -18 139 -18q150 0 150 170v1235h235v-1251q0 -171 -89.5 -259t-258.5 -88q-106 0 -176 25v186zM154 1399q0 63 34.5 97t98.5 34q62 0 96.5 -34t34.5 -97q0 -60 -34.5 -94.5t-96.5 -34.5q-64 0 -98.5 34.5t-34.5 94.5z" /> +<glyph unicode="k" horiz-adv-x="1171" d="M168 0v1556h233v-759l-12 -213h6l133 166l334 356h271l-445 -475l473 -631h-276l-355 485l-129 -106v-379h-233z" /> +<glyph unicode="l" horiz-adv-x="571" d="M168 0v1556h235v-1556h-235z" /> +<glyph unicode="m" horiz-adv-x="1958" d="M168 0v1106h184l33 -145h12q46 79 133.5 122t192.5 43q255 0 338 -174h16q49 82 138 128t204 46q198 0 288.5 -100t90.5 -305v-721h-235v682q0 127 -48.5 189.5t-150.5 62.5q-137 0 -200.5 -85.5t-63.5 -262.5v-586h-236v682q0 127 -48 189.5t-150 62.5 q-136 0 -199.5 -88.5t-63.5 -294.5v-551h-235z" /> +<glyph unicode="n" horiz-adv-x="1300" d="M168 0v1106h184l33 -145h12q50 79 142 122t204 43q398 0 398 -405v-721h-236v680q0 128 -51.5 191t-163.5 63q-149 0 -218 -88t-69 -295v-551h-235z" /> +<glyph unicode="o" horiz-adv-x="1251" d="M102 555q0 269 138 420t389 151q240 0 380 -154.5t140 -416.5q0 -271 -139 -423t-387 -152q-155 0 -274 70t-183 201t-64 304zM344 555q0 -383 283 -383q280 0 280 383q0 379 -282 379q-148 0 -214.5 -98t-66.5 -281z" /> +<glyph unicode="p" horiz-adv-x="1276" d="M168 -492v1598h190q8 -31 33 -148h12q110 168 330 168q207 0 322.5 -150t115.5 -421t-117.5 -423t-324.5 -152q-210 0 -326 151h-14q14 -140 14 -170v-453h-235zM403 555q0 -202 64 -292.5t209 -90.5q122 0 188 100t66 285q0 186 -65.5 281.5t-192.5 95.5 q-140 0 -204.5 -82t-64.5 -262v-35z" /> +<glyph unicode="q" horiz-adv-x="1276" d="M102 551q0 270 118 422.5t325 152.5q104 0 186.5 -38.5t147.5 -126.5h8l26 145h195v-1598h-236v469q0 44 4 93t7 75h-13q-104 -165 -331 -165q-205 0 -321 150.5t-116 420.5zM344 547q0 -379 262 -379q148 0 212.5 85.5t64.5 258.5v37q0 205 -66.5 295t-214.5 90 q-126 0 -192 -100t-66 -287z" /> +<glyph unicode="r" horiz-adv-x="883" d="M168 0v1106h184l31 -195h12q55 99 143.5 157t190.5 58q71 0 117 -10l-23 -219q-50 12 -104 12q-141 0 -228.5 -92t-87.5 -239v-578h-235z" /> +<glyph unicode="s" horiz-adv-x="997" d="M98 827q0 142 114.5 220.5t311.5 78.5q195 0 369 -79l-76 -177q-179 74 -301 74q-186 0 -186 -106q0 -52 48.5 -88t211.5 -99q137 -53 199 -97t92 -101.5t30 -137.5q0 -162 -118 -248.5t-338 -86.5q-221 0 -355 67v203q195 -90 363 -90q217 0 217 131q0 42 -24 70t-79 58 t-153 68q-191 74 -258.5 148t-67.5 192z" /> +<glyph unicode="t" horiz-adv-x="805" d="M39 928v104l162 86l80 234h145v-246h315v-178h-315v-592q0 -85 42.5 -125.5t111.5 -40.5q86 0 172 27v-177q-39 -17 -100.5 -28.5t-127.5 -11.5q-334 0 -334 352v596h-151z" /> +<glyph unicode="u" horiz-adv-x="1300" d="M158 383v723h237v-682q0 -127 52 -190.5t163 -63.5q148 0 217.5 88.5t69.5 296.5v551h236v-1106h-185l-33 145h-12q-49 -77 -139.5 -121t-206.5 -44q-201 0 -300 100t-99 303z" /> +<glyph unicode="v" horiz-adv-x="1096" d="M0 1106h248l225 -643q58 -162 70 -262h8q9 72 70 262l225 643h250l-422 -1106h-254z" /> +<glyph unicode="w" horiz-adv-x="1673" d="M20 1106h240l141 -545q48 -202 68 -346h6q10 73 30.5 167.5t35.5 141.5l168 582h258l163 -582q15 -49 37.5 -150t26.5 -157h8q15 123 70 344l143 545h236l-312 -1106h-264l-143 516q-26 82 -94 381h-9q-58 -270 -92 -383l-147 -514h-260z" /> +<glyph unicode="x" horiz-adv-x="1128" d="M25 0l389 565l-371 541h268l252 -387l254 387h266l-372 -541l391 -565h-266l-273 414l-272 -414h-266z" /> +<glyph unicode="y" horiz-adv-x="1098" d="M0 1106h256l225 -627q51 -134 68 -252h8q9 55 33 133.5t254 745.5h254l-473 -1253q-129 -345 -430 -345q-78 0 -152 17v186q53 -12 121 -12q170 0 239 197l41 104z" /> +<glyph unicode="z" horiz-adv-x="979" d="M68 0v145l559 781h-525v180h789v-164l-547 -762h563v-180h-839z" /> +<glyph unicode="{" horiz-adv-x="791" d="M45 473v191q135 0 200.5 45.5t65.5 138.5v311q0 156 108.5 229.5t325.5 73.5v-182q-114 -5 -165.5 -46.5t-51.5 -123.5v-297q0 -199 -229 -238v-12q229 -36 229 -237v-299q0 -82 51 -124t166 -44v-183q-231 2 -332.5 78.5t-101.5 247.5v285q0 186 -266 186z" /> +<glyph unicode="|" horiz-adv-x="1128" d="M473 -481v2033h180v-2033h-180z" /> +<glyph unicode="}" horiz-adv-x="760" d="M45 -141q95 1 148 38.5t53 129.5v262q0 121 53 187t176 87v12q-229 39 -229 238v297q0 82 -45.5 123.5t-155.5 46.5v182q223 0 320.5 -76.5t97.5 -250.5v-287q0 -100 63.5 -142t188.5 -42v-191q-123 0 -187.5 -42.5t-64.5 -143.5v-307q0 -156 -99.5 -229t-318.5 -75v183z " /> +<glyph unicode="~" d="M96 571v191q99 108 250 108q66 0 125 -13t147 -50q131 -55 220 -55q52 0 114.5 31t120.5 89v-190q-105 -111 -250 -111q-65 0 -127.5 15.5t-146.5 50.5q-127 55 -219 55q-50 0 -111.5 -30t-122.5 -91z" /> +<glyph unicode="&#xa1;" horiz-adv-x="565" d="M133 965q0 69 38 111t110 42t110.5 -40.5t38.5 -112.5q0 -74 -37.5 -113t-111.5 -39q-72 0 -110 39.5t-38 112.5zM141 -371l52 1016h174l51 -1016h-277z" /> +<glyph unicode="&#xa2;" d="M166 741q0 254 100.5 397t306.5 175v170h158v-162q152 -5 283 -66l-70 -188q-146 59 -250 59q-146 0 -216 -95t-70 -288q0 -194 72 -283t210 -89q75 0 142.5 15t154.5 52v-200q-119 -59 -258 -64v-194h-156v200q-207 31 -307 171t-100 390z" /> +<glyph unicode="&#xa3;" d="M72 0v195q98 30 145 96t47 178v184h-188v172h188v256q0 188 113.5 294t312.5 106q194 0 375 -82l-76 -182q-162 71 -284 71q-205 0 -205 -219v-244h397v-172h-397v-182q0 -91 -33 -155t-113 -109h756v-207h-1038z" /> +<glyph unicode="&#xa4;" d="M117 1069l121 119l131 -129q100 63 215 63t213 -65l133 131l121 -117l-131 -133q63 -100 63 -215q0 -119 -63 -217l129 -129l-119 -119l-133 129q-99 -61 -213 -61q-126 0 -215 61l-131 -127l-119 119l131 129q-64 99 -64 215q0 109 64 213zM354 723q0 -98 68 -164.5 t162 -66.5q97 0 165 66.5t68 164.5q0 97 -68 165t-165 68q-93 0 -161.5 -68t-68.5 -165z" /> +<glyph unicode="&#xa5;" d="M18 1462h246l320 -665l321 665h244l-399 -760h227v-151h-281v-154h281v-153h-281v-244h-225v244h-283v153h283v154h-283v151h224z" /> +<glyph unicode="&#xa6;" horiz-adv-x="1128" d="M473 315h180v-796h-180v796zM473 758v794h180v-794h-180z" /> +<glyph unicode="&#xa7;" horiz-adv-x="1026" d="M115 57v179q77 -40 173 -65.5t177 -25.5q235 0 235 131q0 43 -21 70t-71 54t-147 65q-141 55 -206 101.5t-95.5 105t-30.5 135.5q0 80 38.5 145.5t111.5 108.5q-146 83 -146 235q0 129 109.5 202t294.5 73q91 0 174 -17t182 -59l-68 -162q-116 50 -176 63t-121 13 q-194 0 -194 -109q0 -54 55 -93.5t191 -90.5q175 -68 250 -146.5t75 -187.5q0 -177 -139 -266q139 -80 139 -223q0 -142 -118 -224.5t-326 -82.5q-212 0 -346 71zM313 827q0 -45 24 -80t78.5 -69t194.5 -90q109 65 109 168q0 75 -62 126.5t-221 104.5q-54 -16 -88.5 -61.5 t-34.5 -98.5z" /> +<glyph unicode="&#xa8;" horiz-adv-x="1212" d="M293 1399q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM686 1399q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="&#xa9;" horiz-adv-x="1704" d="M100 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM223 731q0 -170 84.5 -315.5t230.5 -229.5t314 -84q170 0 316 85.5t229.5 230t83.5 313.5q0 168 -84.5 314.5 t-231 230.5t-313.5 84q-168 0 -312.5 -83t-230.5 -229t-86 -317zM471 731q0 214 110 337.5t306 123.5q138 0 274 -70l-65 -143q-106 55 -203 55q-111 0 -171 -80.5t-60 -222.5q0 -147 54 -226t177 -79q55 0 118 15t109 36v-158q-115 -51 -235 -51q-197 0 -305.5 120.5 t-108.5 342.5z" /> +<glyph unicode="&#xaa;" horiz-adv-x="754" d="M57 981q0 104 84 159.5t252 61.5l107 4q0 72 -34.5 108t-103.5 36q-90 0 -210 -56l-54 115q144 70 285 70q138 0 207 -62.5t69 -187.5v-447h-112l-29 97q-46 -55 -105 -82t-130 -27q-113 0 -169.5 52.5t-56.5 158.5zM221 983q0 -88 96 -88q91 0 137 41t46 123v43l-99 -4 q-71 -2 -125.5 -34t-54.5 -81z" /> +<glyph unicode="&#xab;" horiz-adv-x="1139" d="M82 535v26l356 432l168 -94l-282 -350l282 -348l-168 -97zM532 535v26l357 432l168 -94l-283 -350l283 -348l-168 -97z" /> +<glyph unicode="&#xac;" d="M96 633v178h977v-555h-178v377h-799z" /> +<glyph unicode="&#xad;" horiz-adv-x="659" d="M72 449v200h514v-200h-514z" /> +<glyph unicode="&#xae;" horiz-adv-x="1704" d="M100 731q0 200 100 375t275 276t377 101q200 0 375 -100t276 -275t101 -377q0 -197 -97 -370t-272 -277t-383 -104q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM223 731q0 -170 84.5 -315.5t230.5 -229.5t314 -84q170 0 316 85.5t229.5 230t83.5 313.5q0 168 -84.5 314.5 t-231 230.5t-313.5 84q-168 0 -312.5 -83t-230.5 -229t-86 -317zM559 279v903h262q174 0 255 -68t81 -205q0 -171 -153 -233l237 -397h-211l-192 346h-90v-346h-189zM748 770h69q74 0 112 35t38 100q0 72 -36.5 100.5t-115.5 28.5h-67v-264z" /> +<glyph unicode="&#xaf;" horiz-adv-x="1024" d="M-6 1556v164h1036v-164h-1036z" /> +<glyph unicode="&#xb0;" horiz-adv-x="877" d="M109 1153q0 135 95 232.5t234 97.5q138 0 233 -96t95 -234q0 -139 -96 -233.5t-232 -94.5q-88 0 -164.5 43.5t-120.5 119.5t-44 165zM262 1153q0 -70 51 -122t125 -52t125 51.5t51 122.5q0 76 -52 127t-124 51t-124 -52t-52 -126z" /> +<glyph unicode="&#xb1;" d="M96 0v178h977v-178h-977zM96 664v178h398v407h180v-407h399v-178h-399v-406h-180v406h-398z" /> +<glyph unicode="&#xb2;" horiz-adv-x="743" d="M51 586v135l230 225q117 112 149.5 165t32.5 112q0 52 -32 79t-83 27q-93 0 -201 -88l-94 121q139 119 309 119q136 0 211.5 -66t75.5 -180q0 -83 -46 -158.5t-183 -202.5l-139 -129h397v-159h-627z" /> +<glyph unicode="&#xb3;" horiz-adv-x="743" d="M45 631v157q145 -79 270 -79q179 0 179 135q0 125 -199 125h-115v133h105q184 0 184 129q0 52 -34.5 80t-90.5 28q-57 0 -105.5 -20t-105.5 -57l-84 114q61 46 134 75.5t171 29.5q134 0 212.5 -61.5t78.5 -168.5q0 -75 -40.5 -122.5t-119.5 -86.5q94 -21 141.5 -76 t47.5 -132q0 -127 -93 -196t-266 -69q-148 0 -270 62z" /> +<glyph unicode="&#xb4;" horiz-adv-x="1212" d="M362 1241v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="&#xb5;" horiz-adv-x="1309" d="M168 -492v1598h235v-684q0 -252 218 -252q146 0 215 88.5t69 296.5v551h236v-1106h-183l-34 147h-13q-48 -83 -119.5 -125t-175.5 -42q-140 0 -219 90h-4q3 -28 6.5 -117t3.5 -125v-320h-235z" /> +<glyph unicode="&#xb6;" horiz-adv-x="1341" d="M113 1042q0 260 109 387t341 127h580v-1816h-137v1663h-191v-1663h-137v819q-62 -18 -146 -18q-216 0 -317.5 125t-101.5 376z" /> +<glyph unicode="&#xb7;" horiz-adv-x="563" d="M133 723q0 73 38 112t110 39q73 0 111 -40.5t38 -110.5q0 -71 -38.5 -112.5t-110.5 -41.5t-110 41t-38 113z" /> +<glyph unicode="&#xb8;" horiz-adv-x="442" d="M0 -340q54 -14 123 -14q54 0 85.5 16.5t31.5 61.5q0 85 -179 110l84 166h152l-41 -88q80 -21 125 -68.5t45 -113.5q0 -222 -305 -222q-66 0 -121 15v137z" /> +<glyph unicode="&#xb9;" horiz-adv-x="743" d="M84 1253l281 209h167v-876h-186v512l3 103l5 91q-17 -18 -40.5 -40t-141.5 -111z" /> +<glyph unicode="&#xba;" horiz-adv-x="780" d="M61 1124q0 169 88.5 262t241.5 93q152 0 240 -94.5t88 -260.5q0 -164 -87.5 -259t-244.5 -95q-150 0 -238 95.5t-88 258.5zM223 1124q0 -111 39 -166t127 -55t127 55t39 166q0 113 -39 167.5t-127 54.5t-127 -54.5t-39 -167.5z" /> +<glyph unicode="&#xbb;" horiz-adv-x="1139" d="M80 201l282 348l-282 350l168 94l358 -432v-26l-358 -431zM530 201l283 348l-283 350l168 94l359 -432v-26l-359 -431z" /> +<glyph unicode="&#xbc;" horiz-adv-x="1700" d="M285 0l858 1462h190l-856 -1462h-192zM60 1253l281 209h167v-876h-186v512l3 103l5 91q-17 -18 -40.5 -40t-141.5 -111zM876 177v127l396 579h188v-563h125v-143h-125v-176h-192v176h-392zM1038 320h230v178q0 97 6 197q-52 -104 -88 -158z" /> +<glyph unicode="&#xbd;" horiz-adv-x="1700" d="M250 0l858 1462h190l-856 -1462h-192zM46 1253l281 209h167v-876h-186v512l3 103l5 91q-17 -18 -40.5 -40t-141.5 -111zM981 1v135l230 225q117 112 149.5 165t32.5 112q0 52 -32 79t-83 27q-93 0 -201 -88l-94 121q139 119 309 119q136 0 211.5 -66t75.5 -180 q0 -83 -46 -158.5t-183 -202.5l-139 -129h397v-159h-627z" /> +<glyph unicode="&#xbe;" horiz-adv-x="1700" d="M367 0l858 1462h190l-856 -1462h-192zM931 177v127l396 579h188v-563h125v-143h-125v-176h-192v176h-392zM1093 320h230v178q0 97 6 197q-52 -104 -88 -158zM55 631v157q145 -79 270 -79q179 0 179 135q0 125 -199 125h-115v133h105q184 0 184 129q0 52 -34.5 80 t-90.5 28q-57 0 -105.5 -20t-105.5 -57l-84 114q61 46 134 75.5t171 29.5q134 0 212.5 -61.5t78.5 -168.5q0 -75 -40.5 -122.5t-119.5 -86.5q94 -21 141.5 -76t47.5 -132q0 -127 -93 -196t-266 -69q-148 0 -270 62z" /> +<glyph unicode="&#xbf;" horiz-adv-x="928" d="M55 -33q0 73 21 130t64 109t157 142q94 76 125 124.5t31 127.5v45h198v-63q0 -106 -41 -181t-143 -155q-124 -98 -155 -147t-31 -124q0 -78 54 -125t161 -47q90 0 174 27.5t166 65.5l82 -179q-220 -110 -424 -110q-207 0 -323 95.5t-116 264.5zM395 965q0 69 38 111 t110 42t110.5 -40.5t38.5 -112.5q0 -74 -37.5 -113t-111.5 -39q-72 0 -110 39.5t-38 112.5z" /> +<glyph unicode="&#xc0;" horiz-adv-x="1354" d="M0 0l547 1468h260l547 -1468h-254l-146 406h-559l-143 -406h-252zM465 612h426l-137 398q-15 40 -41.5 126t-36.5 126q-27 -123 -79 -269zM334 1886v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5z" /> +<glyph unicode="&#xc1;" horiz-adv-x="1354" d="M0 0l547 1468h260l547 -1468h-254l-146 406h-559l-143 -406h-252zM465 612h426l-137 398q-15 40 -41.5 126t-36.5 126q-27 -123 -79 -269zM532 1579v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="&#xc2;" horiz-adv-x="1354" d="M0 0l547 1468h260l547 -1468h-254l-146 406h-559l-143 -406h-252zM465 612h426l-137 398q-15 40 -41.5 126t-36.5 126q-27 -123 -79 -269zM286 1579v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158z" /> +<glyph unicode="&#xc3;" horiz-adv-x="1354" d="M0 0l547 1468h260l547 -1468h-254l-146 406h-559l-143 -406h-252zM465 612h426l-137 398q-15 40 -41.5 126t-36.5 126q-27 -123 -79 -269zM281 1577q12 139 77.5 212t167.5 73q43 0 84 -17.5t80 -39t75.5 -39t70.5 -17.5q79 0 106 115h125q-12 -134 -77 -209.5 t-169 -75.5q-42 0 -82.5 17.5t-79.5 39t-76 39t-71 17.5q-81 0 -109 -115h-122z" /> +<glyph unicode="&#xc4;" horiz-adv-x="1354" d="M0 0l547 1468h260l547 -1468h-254l-146 406h-559l-143 -406h-252zM465 612h426l-137 398q-15 40 -41.5 126t-36.5 126q-27 -123 -79 -269zM363 1737q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM756 1737 q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="&#xc5;" horiz-adv-x="1354" d="M0 0l547 1468h260l547 -1468h-254l-146 406h-559l-143 -406h-252zM465 612h426l-137 398q-15 40 -41.5 126t-36.5 126q-27 -123 -79 -269zM438 1575q0 101 63.5 163.5t172.5 62.5q104 0 171.5 -62t67.5 -162q0 -102 -65.5 -165.5t-173.5 -63.5t-172 62.5t-64 164.5z M567 1575q0 -106 107 -106q46 0 76 27.5t30 78.5q0 50 -30 78.5t-76 28.5q-47 0 -77 -28.5t-30 -78.5z" /> +<glyph unicode="&#xc6;" horiz-adv-x="1868" d="M-2 0l678 1462h1071v-202h-571v-398h532v-200h-532v-459h571v-203h-811v406h-504l-188 -406h-246zM522 612h414v641h-123z" /> +<glyph unicode="&#xc7;" horiz-adv-x="1298" d="M121 731q0 228 83.5 399t241.5 262t371 91q224 0 414 -94l-86 -199q-74 35 -156.5 61.5t-173.5 26.5q-206 0 -324 -146t-118 -403q0 -269 113.5 -407t328.5 -138q93 0 180 18.5t181 47.5v-205q-172 -65 -390 -65q-321 0 -493 194.5t-172 556.5zM526 -340q54 -14 123 -14 q54 0 85.5 16.5t31.5 61.5q0 85 -179 110l84 166h152l-41 -88q80 -21 125 -68.5t45 -113.5q0 -222 -305 -222q-66 0 -121 15v137z" /> +<glyph unicode="&#xc8;" horiz-adv-x="1143" d="M193 0v1462h827v-202h-588v-398h551v-200h-551v-459h588v-203h-827zM289 1886v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5z" /> +<glyph unicode="&#xc9;" horiz-adv-x="1143" d="M193 0v1462h827v-202h-588v-398h551v-200h-551v-459h588v-203h-827zM440 1579v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="&#xca;" horiz-adv-x="1143" d="M193 0v1462h827v-202h-588v-398h551v-200h-551v-459h588v-203h-827zM220 1579v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158z" /> +<glyph unicode="&#xcb;" horiz-adv-x="1143" d="M193 0v1462h827v-202h-588v-398h551v-200h-551v-459h588v-203h-827zM297 1737q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM690 1737q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5 q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="&#xcc;" horiz-adv-x="625" d="M193 0v1462h239v-1462h-239zM-6 1886v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5z" /> +<glyph unicode="&#xcd;" horiz-adv-x="625" d="M193 0v1462h239v-1462h-239zM179 1579v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="&#xce;" horiz-adv-x="625" d="M193 0v1462h239v-1462h-239zM-75 1579v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158z" /> +<glyph unicode="&#xcf;" horiz-adv-x="625" d="M193 0v1462h239v-1462h-239zM1 1737q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM394 1737q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="&#xd0;" horiz-adv-x="1497" d="M47 623v200h146v639h446q347 0 541 -188.5t194 -528.5q0 -360 -201 -552.5t-579 -192.5h-401v623h-146zM432 201h160q530 0 530 536q0 260 -124.5 392.5t-368.5 132.5h-197v-439h307v-200h-307v-422z" /> +<glyph unicode="&#xd1;" horiz-adv-x="1604" d="M193 0v1462h290l717 -1159h6q-2 23 -8 167.5t-6 225.5v766h219v-1462h-293l-719 1165h-8l5 -65q14 -186 14 -340v-760h-217zM414 1577q12 139 77.5 212t167.5 73q43 0 84 -17.5t80 -39t75.5 -39t70.5 -17.5q79 0 106 115h125q-12 -134 -77 -209.5t-169 -75.5 q-42 0 -82.5 17.5t-79.5 39t-76 39t-71 17.5q-81 0 -109 -115h-122z" /> +<glyph unicode="&#xd2;" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q326 0 504 -197t178 -555q0 -357 -178.5 -555t-505.5 -198q-331 0 -508.5 196.5t-177.5 558.5zM375 733q0 -270 109 -409.5t323 -139.5q213 0 321.5 138t108.5 411q0 269 -107.5 408t-320.5 139q-215 0 -324.5 -139t-109.5 -408z M481 1886v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5z" /> +<glyph unicode="&#xd3;" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q326 0 504 -197t178 -555q0 -357 -178.5 -555t-505.5 -198q-331 0 -508.5 196.5t-177.5 558.5zM375 733q0 -270 109 -409.5t323 -139.5q213 0 321.5 138t108.5 411q0 269 -107.5 408t-320.5 139q-215 0 -324.5 -139t-109.5 -408z M657 1579v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="&#xd4;" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q326 0 504 -197t178 -555q0 -357 -178.5 -555t-505.5 -198q-331 0 -508.5 196.5t-177.5 558.5zM375 733q0 -270 109 -409.5t323 -139.5q213 0 321.5 138t108.5 411q0 269 -107.5 408t-320.5 139q-215 0 -324.5 -139t-109.5 -408z M413 1579v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158z" /> +<glyph unicode="&#xd5;" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q326 0 504 -197t178 -555q0 -357 -178.5 -555t-505.5 -198q-331 0 -508.5 196.5t-177.5 558.5zM375 733q0 -270 109 -409.5t323 -139.5q213 0 321.5 138t108.5 411q0 269 -107.5 408t-320.5 139q-215 0 -324.5 -139t-109.5 -408z M410 1577q12 139 77.5 212t167.5 73q43 0 84 -17.5t80 -39t75.5 -39t70.5 -17.5q79 0 106 115h125q-12 -134 -77 -209.5t-169 -75.5q-42 0 -82.5 17.5t-79.5 39t-76 39t-71 17.5q-81 0 -109 -115h-122z" /> +<glyph unicode="&#xd6;" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q326 0 504 -197t178 -555q0 -357 -178.5 -555t-505.5 -198q-331 0 -508.5 196.5t-177.5 558.5zM375 733q0 -270 109 -409.5t323 -139.5q213 0 321.5 138t108.5 411q0 269 -107.5 408t-320.5 139q-215 0 -324.5 -139t-109.5 -408z M496 1737q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM889 1737q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="&#xd7;" d="M131 1049l125 127l328 -326l329 326l125 -123l-329 -330l325 -328l-123 -125l-329 326l-324 -326l-125 125l324 328z" /> +<glyph unicode="&#xd8;" horiz-adv-x="1612" d="M121 735q0 362 178.5 556t509.5 194q199 0 354 -82l90 129l142 -92l-99 -140q195 -199 195 -567q0 -357 -178.5 -555t-505.5 -198q-213 0 -361 81l-94 -137l-141 94l98 144q-188 196 -188 573zM375 733q0 -231 78 -362l587 850q-92 59 -231 59q-215 0 -324.5 -139 t-109.5 -408zM571 244q97 -60 236 -60q213 0 321.5 138t108.5 411q0 225 -80 361z" /> +<glyph unicode="&#xd9;" horiz-adv-x="1520" d="M180 520v942h240v-925q0 -181 84 -267t258 -86q338 0 338 355v923h239v-946q0 -162 -69.5 -283.5t-201 -187t-314.5 -65.5q-272 0 -423 144t-151 396zM417 1886v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5z" /> +<glyph unicode="&#xda;" horiz-adv-x="1520" d="M180 520v942h240v-925q0 -181 84 -267t258 -86q338 0 338 355v923h239v-946q0 -162 -69.5 -283.5t-201 -187t-314.5 -65.5q-272 0 -423 144t-151 396zM600 1579v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="&#xdb;" horiz-adv-x="1520" d="M180 520v942h240v-925q0 -181 84 -267t258 -86q338 0 338 355v923h239v-946q0 -162 -69.5 -283.5t-201 -187t-314.5 -65.5q-272 0 -423 144t-151 396zM366 1579v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158z" /> +<glyph unicode="&#xdc;" horiz-adv-x="1520" d="M180 520v942h240v-925q0 -181 84 -267t258 -86q338 0 338 355v923h239v-946q0 -162 -69.5 -283.5t-201 -187t-314.5 -65.5q-272 0 -423 144t-151 396zM445 1737q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88z M838 1737q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="&#xdd;" horiz-adv-x="1212" d="M0 1462h260l346 -667l346 667h260l-487 -895v-567h-240v559zM450 1579v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="&#xde;" horiz-adv-x="1268" d="M193 0v1462h239v-243h197q268 0 404 -112t136 -331q0 -227 -146 -349t-423 -122h-168v-305h-239zM432 504h133q187 0 273 63t86 203q0 127 -78 188.5t-250 61.5h-164v-516z" /> +<glyph unicode="&#xdf;" horiz-adv-x="1364" d="M168 0v1169q0 193 128.5 295.5t367.5 102.5q225 0 355 -84t130 -230q0 -74 -38.5 -140.5t-104.5 -117.5q-90 -69 -117 -98t-27 -57q0 -30 22.5 -55.5t79.5 -63.5l95 -64q92 -62 135.5 -109.5t65.5 -103.5t22 -127q0 -165 -107 -251t-311 -86q-190 0 -299 65v199 q58 -37 139 -61.5t148 -24.5q192 0 192 151q0 61 -34.5 105t-155.5 118q-119 73 -171 135t-52 146q0 63 34 115.5t105 105.5q75 55 107 97.5t32 93.5q0 72 -67 112.5t-178 40.5q-127 0 -194 -54t-67 -159v-1165h-235z" /> +<glyph unicode="&#xe0;" horiz-adv-x="1188" d="M90 317q0 171 127 258t387 95l191 6v59q0 106 -49.5 158.5t-153.5 52.5q-85 0 -163 -25t-150 -59l-76 168q90 47 197 71.5t202 24.5q211 0 318.5 -92t107.5 -289v-745h-168l-47 154h-8q-80 -101 -161 -137.5t-208 -36.5q-163 0 -254.5 88t-91.5 249zM334 315 q0 -74 44 -114.5t132 -40.5q128 0 205.5 71.5t77.5 200.5v96l-142 -6q-166 -6 -241.5 -55.5t-75.5 -151.5zM259 1548v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5z" /> +<glyph unicode="&#xe1;" horiz-adv-x="1188" d="M90 317q0 171 127 258t387 95l191 6v59q0 106 -49.5 158.5t-153.5 52.5q-85 0 -163 -25t-150 -59l-76 168q90 47 197 71.5t202 24.5q211 0 318.5 -92t107.5 -289v-745h-168l-47 154h-8q-80 -101 -161 -137.5t-208 -36.5q-163 0 -254.5 88t-91.5 249zM334 315 q0 -74 44 -114.5t132 -40.5q128 0 205.5 71.5t77.5 200.5v96l-142 -6q-166 -6 -241.5 -55.5t-75.5 -151.5zM438 1241v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="&#xe2;" horiz-adv-x="1188" d="M90 317q0 171 127 258t387 95l191 6v59q0 106 -49.5 158.5t-153.5 52.5q-85 0 -163 -25t-150 -59l-76 168q90 47 197 71.5t202 24.5q211 0 318.5 -92t107.5 -289v-745h-168l-47 154h-8q-80 -101 -161 -137.5t-208 -36.5q-163 0 -254.5 88t-91.5 249zM334 315 q0 -74 44 -114.5t132 -40.5q128 0 205.5 71.5t77.5 200.5v96l-142 -6q-166 -6 -241.5 -55.5t-75.5 -151.5zM203 1241v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158z" /> +<glyph unicode="&#xe3;" horiz-adv-x="1188" d="M90 317q0 171 127 258t387 95l191 6v59q0 106 -49.5 158.5t-153.5 52.5q-85 0 -163 -25t-150 -59l-76 168q90 47 197 71.5t202 24.5q211 0 318.5 -92t107.5 -289v-745h-168l-47 154h-8q-80 -101 -161 -137.5t-208 -36.5q-163 0 -254.5 88t-91.5 249zM334 315 q0 -74 44 -114.5t132 -40.5q128 0 205.5 71.5t77.5 200.5v96l-142 -6q-166 -6 -241.5 -55.5t-75.5 -151.5zM208 1239q12 139 77.5 212t167.5 73q43 0 84 -17.5t80 -39t75.5 -39t70.5 -17.5q79 0 106 115h125q-12 -134 -77 -209.5t-169 -75.5q-42 0 -82.5 17.5t-79.5 39 t-76 39t-71 17.5q-81 0 -109 -115h-122z" /> +<glyph unicode="&#xe4;" horiz-adv-x="1188" d="M90 317q0 171 127 258t387 95l191 6v59q0 106 -49.5 158.5t-153.5 52.5q-85 0 -163 -25t-150 -59l-76 168q90 47 197 71.5t202 24.5q211 0 318.5 -92t107.5 -289v-745h-168l-47 154h-8q-80 -101 -161 -137.5t-208 -36.5q-163 0 -254.5 88t-91.5 249zM334 315 q0 -74 44 -114.5t132 -40.5q128 0 205.5 71.5t77.5 200.5v96l-142 -6q-166 -6 -241.5 -55.5t-75.5 -151.5zM282 1399q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM675 1399q0 62 33.5 89.5t81.5 27.5q53 0 85 -31 t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="&#xe5;" horiz-adv-x="1188" d="M90 317q0 171 127 258t387 95l191 6v59q0 106 -49.5 158.5t-153.5 52.5q-85 0 -163 -25t-150 -59l-76 168q90 47 197 71.5t202 24.5q211 0 318.5 -92t107.5 -289v-745h-168l-47 154h-8q-80 -101 -161 -137.5t-208 -36.5q-163 0 -254.5 88t-91.5 249zM334 315 q0 -74 44 -114.5t132 -40.5q128 0 205.5 71.5t77.5 200.5v96l-142 -6q-166 -6 -241.5 -55.5t-75.5 -151.5zM366 1466q0 101 63.5 163.5t172.5 62.5q104 0 171.5 -62t67.5 -162q0 -102 -65.5 -165.5t-173.5 -63.5t-172 62.5t-64 164.5zM495 1466q0 -106 107 -106 q46 0 76 27.5t30 78.5q0 50 -30 78.5t-76 28.5q-47 0 -77 -28.5t-30 -78.5z" /> +<glyph unicode="&#xe6;" horiz-adv-x="1817" d="M90 317q0 172 121.5 258.5t370.5 94.5l188 6v76q0 194 -201 194q-141 0 -307 -82l-74 166q88 47 192.5 71.5t203.5 24.5q241 0 340 -155q120 155 346 155q206 0 328 -134.5t122 -362.5v-127h-712q10 -336 301 -336q184 0 356 80v-191q-86 -41 -171.5 -58t-195.5 -17 q-140 0 -248.5 54.5t-175.5 164.5q-94 -125 -190.5 -172t-241.5 -47q-165 0 -258.5 90t-93.5 247zM334 315q0 -155 166 -155q124 0 196 72.5t72 199.5v96l-135 -6q-155 -6 -227 -54.5t-72 -152.5zM1014 670h473q0 130 -58.5 204t-162.5 74q-112 0 -177.5 -69.5t-74.5 -208.5 z" /> +<glyph unicode="&#xe7;" horiz-adv-x="1014" d="M102 547q0 279 136.5 429t394.5 150q175 0 315 -65l-71 -189q-149 58 -246 58q-287 0 -287 -381q0 -186 71.5 -279.5t209.5 -93.5q157 0 297 78v-205q-63 -37 -134.5 -53t-173.5 -16q-251 0 -381.5 146.5t-130.5 420.5zM356 -340q54 -14 123 -14q54 0 85.5 16.5 t31.5 61.5q0 85 -179 110l84 166h152l-41 -88q80 -21 125 -68.5t45 -113.5q0 -222 -305 -222q-66 0 -121 15v137z" /> +<glyph unicode="&#xe8;" horiz-adv-x="1180" d="M102 545q0 271 135 426t371 155q219 0 346 -133t127 -366v-127h-737q5 -161 87 -247.5t231 -86.5q98 0 182.5 18.5t181.5 61.5v-191q-86 -41 -174 -58t-201 -17q-258 0 -403.5 150.5t-145.5 414.5zM348 670h502q-2 137 -66 207.5t-176 70.5t-179.5 -71t-80.5 -207z M281 1548v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5z" /> +<glyph unicode="&#xe9;" horiz-adv-x="1180" d="M102 545q0 271 135 426t371 155q219 0 346 -133t127 -366v-127h-737q5 -161 87 -247.5t231 -86.5q98 0 182.5 18.5t181.5 61.5v-191q-86 -41 -174 -58t-201 -17q-258 0 -403.5 150.5t-145.5 414.5zM348 670h502q-2 137 -66 207.5t-176 70.5t-179.5 -71t-80.5 -207z M458 1241v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="&#xea;" horiz-adv-x="1180" d="M102 545q0 271 135 426t371 155q219 0 346 -133t127 -366v-127h-737q5 -161 87 -247.5t231 -86.5q98 0 182.5 18.5t181.5 61.5v-191q-86 -41 -174 -58t-201 -17q-258 0 -403.5 150.5t-145.5 414.5zM348 670h502q-2 137 -66 207.5t-176 70.5t-179.5 -71t-80.5 -207z M227 1241v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158z" /> +<glyph unicode="&#xeb;" horiz-adv-x="1180" d="M102 545q0 271 135 426t371 155q219 0 346 -133t127 -366v-127h-737q5 -161 87 -247.5t231 -86.5q98 0 182.5 18.5t181.5 61.5v-191q-86 -41 -174 -58t-201 -17q-258 0 -403.5 150.5t-145.5 414.5zM348 670h502q-2 137 -66 207.5t-176 70.5t-179.5 -71t-80.5 -207z M307 1399q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM700 1399q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="&#xec;" horiz-adv-x="571" d="M168 0v1106h235v-1106h-235zM-69 1548v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5z" /> +<glyph unicode="&#xed;" horiz-adv-x="571" d="M168 0v1106h235v-1106h-235zM156 1241v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="&#xee;" horiz-adv-x="571" d="M168 0v1106h235v-1106h-235zM-100 1241v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158z" /> +<glyph unicode="&#xef;" horiz-adv-x="571" d="M168 0v1106h235v-1106h-235zM-25 1399q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM368 1399q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="&#xf0;" horiz-adv-x="1243" d="M102 481q0 231 131 365.5t351 134.5q214 0 301 -111l8 4q-62 189 -227 345l-250 -150l-88 133l204 119q-86 59 -167 102l84 146q140 -63 258 -144l231 138l88 -129l-188 -113q152 -140 231.5 -330t79.5 -424q0 -279 -137.5 -433t-388.5 -154q-235 0 -378 136t-143 365z M342 477q0 -153 74 -234t211 -81q148 0 215 91t67 269q0 127 -75.5 202t-206.5 75q-151 0 -218 -82t-67 -240z" /> +<glyph unicode="&#xf1;" horiz-adv-x="1300" d="M168 0v1106h184l33 -145h12q50 79 142 122t204 43q398 0 398 -405v-721h-236v680q0 128 -51.5 191t-163.5 63q-149 0 -218 -88t-69 -295v-551h-235zM269 1239q12 139 77.5 212t167.5 73q43 0 84 -17.5t80 -39t75.5 -39t70.5 -17.5q79 0 106 115h125q-12 -134 -77 -209.5 t-169 -75.5q-42 0 -82.5 17.5t-79.5 39t-76 39t-71 17.5q-81 0 -109 -115h-122z" /> +<glyph unicode="&#xf2;" horiz-adv-x="1251" d="M102 555q0 269 138 420t389 151q240 0 380 -154.5t140 -416.5q0 -271 -139 -423t-387 -152q-155 0 -274 70t-183 201t-64 304zM344 555q0 -383 283 -383q280 0 280 383q0 379 -282 379q-148 0 -214.5 -98t-66.5 -281zM293 1548v21h273q38 -70 103.5 -161t109.5 -142v-25 h-158q-69 52 -174.5 150.5t-153.5 156.5z" /> +<glyph unicode="&#xf3;" horiz-adv-x="1251" d="M102 555q0 269 138 420t389 151q240 0 380 -154.5t140 -416.5q0 -271 -139 -423t-387 -152q-155 0 -274 70t-183 201t-64 304zM344 555q0 -383 283 -383q280 0 280 383q0 379 -282 379q-148 0 -214.5 -98t-66.5 -281zM473 1241v25q57 70 117.5 156t95.5 147h273v-21 q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="&#xf4;" horiz-adv-x="1251" d="M102 555q0 269 138 420t389 151q240 0 380 -154.5t140 -416.5q0 -271 -139 -423t-387 -152q-155 0 -274 70t-183 201t-64 304zM344 555q0 -383 283 -383q280 0 280 383q0 379 -282 379q-148 0 -214.5 -98t-66.5 -281zM239 1241v25q191 198 254 303h260q63 -110 256 -303 v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158z" /> +<glyph unicode="&#xf5;" horiz-adv-x="1251" d="M102 555q0 269 138 420t389 151q240 0 380 -154.5t140 -416.5q0 -271 -139 -423t-387 -152q-155 0 -274 70t-183 201t-64 304zM344 555q0 -383 283 -383q280 0 280 383q0 379 -282 379q-148 0 -214.5 -98t-66.5 -281zM235 1239q12 139 77.5 212t167.5 73q43 0 84 -17.5 t80 -39t75.5 -39t70.5 -17.5q79 0 106 115h125q-12 -134 -77 -209.5t-169 -75.5q-42 0 -82.5 17.5t-79.5 39t-76 39t-71 17.5q-81 0 -109 -115h-122z" /> +<glyph unicode="&#xf6;" horiz-adv-x="1251" d="M102 555q0 269 138 420t389 151q240 0 380 -154.5t140 -416.5q0 -271 -139 -423t-387 -152q-155 0 -274 70t-183 201t-64 304zM344 555q0 -383 283 -383q280 0 280 383q0 379 -282 379q-148 0 -214.5 -98t-66.5 -281zM311 1399q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31 t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM704 1399q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="&#xf7;" d="M96 633v178h977v-178h-977zM457 373q0 64 31.5 99.5t95.5 35.5q61 0 93 -36t32 -99t-34 -100t-91 -37q-60 0 -93.5 35.5t-33.5 101.5zM457 1071q0 64 31.5 99.5t95.5 35.5q61 0 93 -36t32 -99t-34 -100t-91 -37q-60 0 -93.5 35.5t-33.5 101.5z" /> +<glyph unicode="&#xf8;" horiz-adv-x="1251" d="M102 555q0 269 138 420t389 151q144 0 258 -63l69 100l136 -92l-78 -108q135 -152 135 -408q0 -271 -139 -423t-387 -152q-144 0 -250 57l-76 -109l-135 90l82 117q-142 155 -142 420zM344 555q0 -135 37 -219l391 559q-60 39 -147 39q-148 0 -214.5 -98t-66.5 -281z M487 205q54 -33 140 -33q280 0 280 383q0 121 -33 203z" /> +<glyph unicode="&#xf9;" horiz-adv-x="1300" d="M158 383v723h237v-682q0 -127 52 -190.5t163 -63.5q148 0 217.5 88.5t69.5 296.5v551h236v-1106h-185l-33 145h-12q-49 -77 -139.5 -121t-206.5 -44q-201 0 -300 100t-99 303zM289 1548v21h273q38 -70 103.5 -161t109.5 -142v-25h-158q-69 52 -174.5 150.5t-153.5 156.5z " /> +<glyph unicode="&#xfa;" horiz-adv-x="1300" d="M158 383v723h237v-682q0 -127 52 -190.5t163 -63.5q148 0 217.5 88.5t69.5 296.5v551h236v-1106h-185l-33 145h-12q-49 -77 -139.5 -121t-206.5 -44q-201 0 -300 100t-99 303zM501 1241v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z " /> +<glyph unicode="&#xfb;" horiz-adv-x="1300" d="M158 383v723h237v-682q0 -127 52 -190.5t163 -63.5q148 0 217.5 88.5t69.5 296.5v551h236v-1106h-185l-33 145h-12q-49 -77 -139.5 -121t-206.5 -44q-201 0 -300 100t-99 303zM260 1241v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180 q-103 -103 -225 -180h-158z" /> +<glyph unicode="&#xfc;" horiz-adv-x="1300" d="M158 383v723h237v-682q0 -127 52 -190.5t163 -63.5q148 0 217.5 88.5t69.5 296.5v551h236v-1106h-185l-33 145h-12q-49 -77 -139.5 -121t-206.5 -44q-201 0 -300 100t-99 303zM332 1399q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32 q-48 0 -81.5 29t-33.5 88zM725 1399q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="&#xfd;" horiz-adv-x="1098" d="M0 1106h256l225 -627q51 -134 68 -252h8q9 55 33 133.5t254 745.5h254l-473 -1253q-129 -345 -430 -345q-78 0 -152 17v186q53 -12 121 -12q170 0 239 197l41 104zM401 1241v25q57 70 117.5 156t95.5 147h273v-21q-52 -61 -155.5 -157.5t-174.5 -149.5h-156z" /> +<glyph unicode="&#xfe;" horiz-adv-x="1276" d="M168 -492v2048h235v-430l-7 -138l-3 -27h10q61 86 142.5 125.5t187.5 39.5q206 0 322 -151t116 -420q0 -272 -116.5 -423.5t-321.5 -151.5q-219 0 -330 149h-14l8 -72l6 -92v-457h-235zM403 555q0 -202 64 -292.5t209 -90.5q254 0 254 385q0 190 -61.5 283.5t-194.5 93.5 q-142 0 -206.5 -82t-64.5 -260v-37z" /> +<glyph unicode="&#xff;" horiz-adv-x="1098" d="M0 1106h256l225 -627q51 -134 68 -252h8q9 55 33 133.5t254 745.5h254l-473 -1253q-129 -345 -430 -345q-78 0 -152 17v186q53 -12 121 -12q170 0 239 197l41 104zM239 1399q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29 t-33.5 88zM632 1399q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="&#x131;" horiz-adv-x="571" d="M168 0v1106h235v-1106h-235z" /> +<glyph unicode="&#x152;" horiz-adv-x="1942" d="M121 735q0 360 172 555t491 195q115 0 209 -23h826v-202h-576v-398h539v-200h-539v-459h576v-203h-820q-102 -20 -211 -20q-320 0 -493.5 196.5t-173.5 558.5zM371 733q0 -269 106 -409t314 -140q129 0 213 35v1024q-80 37 -211 37q-208 0 -315 -139t-107 -408z" /> +<glyph unicode="&#x153;" horiz-adv-x="1966" d="M102 555q0 272 137 421.5t382 149.5q121 0 223 -49t168 -145q131 194 379 194q221 0 349 -133.5t128 -365.5v-127h-738q11 -164 85.5 -249t228.5 -85q102 0 187 18.5t181 61.5v-191q-84 -40 -171.5 -57.5t-202.5 -17.5q-281 0 -420 194q-132 -194 -400 -194 q-236 0 -376 155t-140 420zM344 555q0 -189 65.5 -286t211.5 -97q141 0 206.5 95.5t65.5 283.5q0 192 -66 287.5t-211 95.5q-143 0 -207.5 -95t-64.5 -284zM1137 670h497q0 134 -63 206t-178 72q-110 0 -177.5 -69.5t-78.5 -208.5z" /> +<glyph unicode="&#x178;" horiz-adv-x="1212" d="M0 1462h260l346 -667l346 667h260l-487 -895v-567h-240v559zM293 1737q0 62 33.5 89.5t81.5 27.5q53 0 84.5 -31t31.5 -86q0 -53 -32 -85t-84 -32q-48 0 -81.5 29t-33.5 88zM686 1737q0 62 33.5 89.5t81.5 27.5q53 0 85 -31t32 -86q0 -54 -33 -85.5t-84 -31.5 q-48 0 -81.5 29t-33.5 88z" /> +<glyph unicode="&#x2c6;" horiz-adv-x="1227" d="M227 1241v25q191 198 254 303h260q63 -110 256 -303v-25h-159q-123 73 -228 180q-103 -103 -225 -180h-158z" /> +<glyph unicode="&#x2da;" horiz-adv-x="1182" d="M352 1466q0 101 63.5 163.5t172.5 62.5q104 0 171.5 -62t67.5 -162q0 -102 -65.5 -165.5t-173.5 -63.5t-172 62.5t-64 164.5zM481 1466q0 -106 107 -106q46 0 76 27.5t30 78.5q0 50 -30 78.5t-76 28.5q-47 0 -77 -28.5t-30 -78.5z" /> +<glyph unicode="&#x2dc;" horiz-adv-x="1227" d="M236 1239q12 139 77.5 212t167.5 73q43 0 84 -17.5t80 -39t75.5 -39t70.5 -17.5q79 0 106 115h125q-12 -134 -77 -209.5t-169 -75.5q-42 0 -82.5 17.5t-79.5 39t-76 39t-71 17.5q-81 0 -109 -115h-122z" /> +<glyph unicode="&#x2000;" horiz-adv-x="953" /> +<glyph unicode="&#x2001;" horiz-adv-x="1907" /> +<glyph unicode="&#x2002;" horiz-adv-x="953" /> +<glyph unicode="&#x2003;" horiz-adv-x="1907" /> +<glyph unicode="&#x2004;" horiz-adv-x="635" /> +<glyph unicode="&#x2005;" horiz-adv-x="476" /> +<glyph unicode="&#x2006;" horiz-adv-x="317" /> +<glyph unicode="&#x2007;" horiz-adv-x="317" /> +<glyph unicode="&#x2008;" horiz-adv-x="238" /> +<glyph unicode="&#x2009;" horiz-adv-x="381" /> +<glyph unicode="&#x200a;" horiz-adv-x="105" /> +<glyph unicode="&#x2010;" horiz-adv-x="659" d="M72 449v200h514v-200h-514z" /> +<glyph unicode="&#x2011;" horiz-adv-x="659" d="M72 449v200h514v-200h-514z" /> +<glyph unicode="&#x2012;" horiz-adv-x="659" d="M72 449v200h514v-200h-514z" /> +<glyph unicode="&#x2013;" horiz-adv-x="1024" d="M82 455v190h860v-190h-860z" /> +<glyph unicode="&#x2014;" horiz-adv-x="2048" d="M82 455v190h1884v-190h-1884z" /> +<glyph unicode="&#x2018;" horiz-adv-x="395" d="M25 983q20 83 71 224t105 255h170q-64 -256 -101 -501h-233z" /> +<glyph unicode="&#x2019;" horiz-adv-x="395" d="M25 961q69 289 100 501h231l15 -22q-53 -209 -176 -479h-170z" /> +<glyph unicode="&#x201a;" horiz-adv-x="549" d="M63 -264q69 270 103 502h231l15 -23q-48 -186 -176 -479h-173z" /> +<glyph unicode="&#x201c;" horiz-adv-x="813" d="M25 983q20 83 71 224t105 255h170q-64 -256 -101 -501h-233zM440 983q53 203 178 479h170q-69 -296 -100 -501h-233z" /> +<glyph unicode="&#x201d;" horiz-adv-x="813" d="M25 961q69 289 100 501h231l15 -22q-53 -209 -176 -479h-170zM440 961q69 271 103 501h231l14 -22q-53 -209 -176 -479h-172z" /> +<glyph unicode="&#x201e;" horiz-adv-x="944" d="M43 -264q66 260 102 502h232l14 -23q-55 -214 -176 -479h-172zM461 -264q66 260 102 502h232l14 -23q-48 -186 -176 -479h-172z" /> +<glyph unicode="&#x2022;" horiz-adv-x="770" d="M131 748q0 138 66 210t188 72q121 0 187.5 -72.5t66.5 -209.5q0 -135 -67 -209t-187 -74t-187 72.5t-67 210.5z" /> +<glyph unicode="&#x2026;" horiz-adv-x="1677" d="M133 125q0 73 38 112t110 39q73 0 111 -40.5t38 -110.5q0 -71 -38.5 -112.5t-110.5 -41.5t-110 41t-38 113zM690 125q0 73 38 112t110 39q73 0 111 -40.5t38 -110.5q0 -71 -38.5 -112.5t-110.5 -41.5t-110 41t-38 113zM1247 125q0 73 38 112t110 39q73 0 111 -40.5 t38 -110.5q0 -71 -38.5 -112.5t-110.5 -41.5t-110 41t-38 113z" /> +<glyph unicode="&#x202f;" horiz-adv-x="381" /> +<glyph unicode="&#x2039;" horiz-adv-x="688" d="M82 535v26l356 432l168 -94l-282 -350l282 -348l-168 -97z" /> +<glyph unicode="&#x203a;" horiz-adv-x="688" d="M80 201l282 348l-282 350l168 94l358 -432v-26l-358 -431z" /> +<glyph unicode="&#x2044;" horiz-adv-x="266" d="M-393 0l858 1462h190l-856 -1462h-192z" /> +<glyph unicode="&#x205f;" horiz-adv-x="476" /> +<glyph unicode="&#x2074;" horiz-adv-x="743" d="M16 762v127l396 579h188v-563h125v-143h-125v-176h-192v176h-392zM178 905h230v178q0 97 6 197q-52 -104 -88 -158z" /> +<glyph unicode="&#x20ac;" horiz-adv-x="1188" d="M63 494v153h136l-2 37v37l2 65h-136v154h150q38 251 191 394t395 143q200 0 358 -88l-84 -187q-154 76 -274 76q-141 0 -230.5 -84t-119.5 -254h456v-154h-471l-2 -45v-55l2 -39h408v-153h-391q64 -312 364 -312q143 0 293 62v-203q-131 -61 -305 -61q-241 0 -391.5 132 t-196.5 382h-152z" /> +<glyph unicode="&#x2122;" horiz-adv-x="1561" d="M27 1333v129h553v-129h-205v-592h-146v592h-202zM635 741v721h217l178 -534l187 534h210v-721h-147v414l4 129h-6l-193 -543h-122l-185 543h-6l4 -119v-424h-141z" /> +<glyph unicode="&#xe000;" horiz-adv-x="1105" d="M0 1105h1105v-1105h-1105v1105z" /> +<glyph unicode="&#xfb01;" horiz-adv-x="1315" d="M35 928v110l182 72v72q0 196 92 290.5t281 94.5q124 0 244 -41l-62 -178q-87 28 -166 28q-80 0 -116.5 -49.5t-36.5 -148.5v-72h270v-178h-270v-928h-236v928h-182zM897 1399q0 63 34.5 97t98.5 34q62 0 96.5 -34t34.5 -97q0 -60 -34.5 -94.5t-96.5 -34.5 q-64 0 -98.5 34.5t-34.5 94.5zM911 0v1106h235v-1106h-235z" /> +<glyph unicode="&#xfb02;" horiz-adv-x="1315" d="M35 928v110l182 72v72q0 196 92 290.5t281 94.5q124 0 244 -41l-62 -178q-87 28 -166 28q-80 0 -116.5 -49.5t-36.5 -148.5v-72h270v-178h-270v-928h-236v928h-182zM911 0v1556h235v-1556h-235z" /> +<glyph unicode="&#xfb03;" horiz-adv-x="2058" d="M35 928v110l182 72v72q0 196 92 290.5t281 94.5q124 0 244 -41l-62 -178q-87 28 -166 28q-80 0 -116.5 -49.5t-36.5 -148.5v-72h270v-178h-270v-928h-236v928h-182zM778 928v110l182 72v72q0 196 92 290.5t281 94.5q124 0 244 -41l-62 -178q-87 28 -166 28 q-80 0 -116.5 -49.5t-36.5 -148.5v-72h270v-178h-270v-928h-236v928h-182zM1641 1399q0 63 34.5 97t98.5 34q62 0 96.5 -34t34.5 -97q0 -60 -34.5 -94.5t-96.5 -34.5q-64 0 -98.5 34.5t-34.5 94.5zM1655 0v1106h235v-1106h-235z" /> +<glyph unicode="&#xfb04;" horiz-adv-x="2058" d="M35 928v110l182 72v72q0 196 92 290.5t281 94.5q124 0 244 -41l-62 -178q-87 28 -166 28q-80 0 -116.5 -49.5t-36.5 -148.5v-72h270v-178h-270v-928h-236v928h-182zM778 928v110l182 72v72q0 196 92 290.5t281 94.5q124 0 244 -41l-62 -178q-87 28 -166 28 q-80 0 -116.5 -49.5t-36.5 -148.5v-72h270v-178h-270v-928h-236v928h-182zM1655 0v1556h235v-1556h-235z" /> +</font> +</defs></svg> +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-Semibold-webfont.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.svg b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.svg @@ -0,0 +1,251 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > +<svg xmlns="http://www.w3.org/2000/svg"> +<metadata> +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom +</metadata> +<defs> +<font id="OpenSansSemiboldItalic" horiz-adv-x="1128" > +<font-face units-per-em="2048" ascent="1638" descent="-410" /> +<missing-glyph horiz-adv-x="532" /> +<glyph unicode=" " horiz-adv-x="532" /> +<glyph unicode="&#x09;" horiz-adv-x="532" /> +<glyph unicode="&#xa0;" horiz-adv-x="532" /> +<glyph unicode="!" horiz-adv-x="557" d="M33 96q0 80 45.5 130t130.5 50q57 0 91 -32.5t34 -93.5q0 -79 -47 -128t-123 -49q-62 0 -96.5 33.5t-34.5 89.5zM160 444l168 1018h272l-264 -1018h-176z" /> +<glyph unicode="&#x22;" horiz-adv-x="858" d="M213 934l72 528h231l-151 -528h-152zM588 934l74 528h231l-152 -528h-153z" /> +<glyph unicode="#" horiz-adv-x="1323" d="M51 418l17 168h280l84 286h-264l16 168h295l121 422h178l-121 -422h252l121 422h174l-121 -422h252l-14 -168h-285l-84 -286h271l-15 -168h-303l-121 -418h-180l123 418h-248l-121 -418h-174l117 418h-250zM526 586h250l82 286h-250z" /> +<glyph unicode="$" d="M61 172v209q78 -42 179.5 -70t193.5 -30l84 387q-156 56 -223.5 138.5t-67.5 199.5q0 167 118.5 267.5t324.5 117.5l37 163h135l-35 -165q161 -16 289 -82l-86 -185q-134 66 -244 74l-80 -371q128 -51 186.5 -95t86.5 -101t28 -135q0 -172 -119.5 -277t-337.5 -125 l-45 -211h-135l45 211q-197 13 -334 80zM451 1016q0 -98 110 -139l68 319q-89 -11 -133.5 -57.5t-44.5 -122.5zM571 285q86 11 136.5 60t50.5 126q0 101 -115 145z" /> +<glyph unicode="%" horiz-adv-x="1688" d="M141 872q0 166 53 313.5t142.5 222.5t208.5 75q127 0 193.5 -76t66.5 -221q0 -160 -55.5 -313.5t-146.5 -230.5t-206 -77q-124 0 -190 79t-66 228zM231 0l1086 1462h194l-1085 -1462h-195zM334 866q0 -135 80 -135q52 0 95.5 58t73 175.5t29.5 219.5q0 131 -82 131 q-55 0 -99 -61t-70.5 -173t-26.5 -215zM940 279q0 171 53 320t142.5 223.5t207.5 74.5q127 0 195 -75t68 -218q0 -161 -55.5 -315.5t-146.5 -231.5t-204 -77q-127 0 -193.5 76.5t-66.5 222.5zM1133 281q0 -134 81 -134q52 0 96 58.5t73.5 174.5t29.5 220q0 131 -84 131 q-52 0 -95.5 -57.5t-72 -171t-28.5 -221.5z" /> +<glyph unicode="&#x26;" horiz-adv-x="1411" d="M66 350q0 147 85.5 254t286.5 205q-88 151 -88 283q0 180 112.5 286.5t297.5 106.5q160 0 252 -81t92 -218q0 -129 -89.5 -230t-293.5 -192l235 -326q109 112 181 295h233q-113 -270 -297 -454l205 -279h-277l-94 131q-106 -80 -211 -115.5t-229 -35.5 q-190 0 -295.5 97.5t-105.5 272.5zM305 371q0 -86 56 -140.5t147 -54.5q77 0 147 27t144 82l-264 381q-133 -74 -181.5 -141.5t-48.5 -153.5zM567 1102q0 -109 62 -201q147 75 199.5 133.5t52.5 126.5q0 66 -36 101.5t-97 35.5q-87 0 -134 -54t-47 -142z" /> +<glyph unicode="'" horiz-adv-x="483" d="M213 934l72 528h231l-151 -528h-152z" /> +<glyph unicode="(" horiz-adv-x="639" d="M78 276q0 343 124.5 632.5t379.5 553.5h209q-498 -548 -498 -1190q0 -329 115 -596h-183q-147 261 -147 600z" /> +<glyph unicode=")" horiz-adv-x="639" d="M-154 -324q498 548 498 1190q0 327 -115 596h183q147 -265 147 -602q0 -342 -123 -629.5t-381 -554.5h-209z" /> +<glyph unicode="*" horiz-adv-x="1122" d="M193 1167l71 195l354 -178l37 383l213 -43l-116 -367l403 23l-12 -205l-367 45l170 -361l-205 -61l-102 371l-227 -312l-162 144l293 266z" /> +<glyph unicode="+" d="M117 631v180h379v381h180v-381h377v-180h-377v-375h-180v375h-379z" /> +<glyph unicode="," horiz-adv-x="530" d="M-102 -264q105 238 200 502h236l8 -23q-125 -260 -266 -479h-178z" /> +<glyph unicode="-" horiz-adv-x="649" d="M47 446l45 203h502l-45 -203h-502z" /> +<glyph unicode="." horiz-adv-x="551" d="M33 94q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -78 -47.5 -129.5t-124.5 -51.5q-66 0 -97.5 35.5t-31.5 87.5z" /> +<glyph unicode="/" horiz-adv-x="788" d="M-92 0l811 1462h233l-811 -1462h-233z" /> +<glyph unicode="0" d="M92 471q0 284 83 526t222.5 365t321.5 123q187 0 284 -118.5t97 -354.5q0 -306 -79 -546.5t-219 -363t-325 -122.5q-194 0 -289.5 127.5t-95.5 363.5zM330 469q0 -143 39 -218t129 -75q100 0 182.5 113.5t132 316.5t49.5 414q0 268 -162 268q-97 0 -180 -112 t-136.5 -312.5t-53.5 -394.5z" /> +<glyph unicode="1" d="M242 1145l508 317h198l-311 -1462h-238l189 870q28 150 82 324q-57 -55 -135 -102l-187 -117z" /> +<glyph unicode="2" d="M-18 0l36 180l471 422q176 159 238.5 231t90.5 133.5t28 131.5q0 85 -49.5 134.5t-139.5 49.5q-70 0 -139 -30t-170 -109l-115 160q120 97 231 138.5t228 41.5q181 0 288 -93t107 -251q0 -108 -39 -201t-123 -190.5t-284 -268.5l-311 -264v-8h622l-41 -207h-929z" /> +<glyph unicode="3" d="M31 59v215q84 -49 185.5 -75.5t195.5 -26.5q157 0 245 71.5t88 196.5q0 219 -278 219h-133l37 183h106q164 0 267.5 74.5t103.5 199.5q0 79 -49.5 124.5t-139.5 45.5q-72 0 -146.5 -25.5t-162.5 -84.5l-104 161q120 81 225.5 113.5t226.5 32.5q183 0 286 -88.5 t103 -241.5q0 -158 -99 -264t-269 -137v-7q127 -24 196.5 -106t69.5 -205q0 -133 -68 -236.5t-196.5 -160.5t-304.5 -57q-225 0 -385 79z" /> +<glyph unicode="4" d="M-4 317l37 197l803 952h254l-201 -952h201l-43 -197h-201l-68 -317h-229l69 317h-622zM262 514h397l68 309q31 136 100 377h-8q-51 -86 -135 -186z" /> +<glyph unicode="5" d="M53 59v217q167 -100 342 -100q173 0 270 83t97 230q0 105 -62 168.5t-188 63.5q-95 0 -225 -35l-88 68l200 708h713l-45 -209h-506l-106 -364q93 18 155 18q181 0 288.5 -103.5t107.5 -285.5q0 -161 -70 -283t-204 -188.5t-324 -66.5q-214 0 -355 79z" /> +<glyph unicode="6" d="M111 446q0 205 60.5 406t165 343t251 215t342.5 73q117 0 203 -25l-43 -194q-72 22 -181 22q-205 0 -337 -129.5t-197 -392.5h6q125 170 326 170q156 0 243.5 -99t87.5 -272q0 -162 -68.5 -301t-185.5 -210.5t-270 -71.5q-194 0 -298.5 120t-104.5 346zM340 418 q0 -110 49.5 -177t140.5 -67q81 0 143 48.5t96 134.5t34 188q0 200 -178 200q-51 0 -95.5 -19t-79 -48t-58.5 -64.5t-39 -82t-13 -113.5z" /> +<glyph unicode="7" d="M125 0l754 1257h-674l43 205h932l-33 -168l-758 -1294h-264z" /> +<glyph unicode="8" d="M76 348q0 297 368 432q-91 70 -130.5 145t-39.5 162q0 179 127 288.5t330 109.5q179 0 283 -89t104 -239q0 -132 -79 -229.5t-248 -163.5q120 -78 172.5 -165.5t52.5 -201.5q0 -121 -61.5 -216.5t-175.5 -148t-271 -52.5q-203 0 -317.5 100t-114.5 268zM311 369 q0 -93 59 -149t158 -56q115 0 184.5 64t69.5 167q0 91 -48.5 157.5t-139.5 119.5q-149 -54 -216 -126.5t-67 -176.5zM504 1096q0 -83 39 -137t104 -93q115 43 177.5 105t62.5 157q0 81 -48 126.5t-128 45.5q-93 0 -150 -56t-57 -148z" /> +<glyph unicode="9" d="M92 12v207q121 -43 236 -43q188 0 306 123t177 389h-6q-113 -160 -305 -160q-165 0 -255.5 102t-90.5 288q0 156 67 289t186.5 204.5t274.5 71.5q192 0 294.5 -119.5t102.5 -345.5q0 -205 -58 -414.5t-152.5 -349t-226 -207t-310.5 -67.5q-133 0 -240 32zM387 932 q0 -105 46 -160t134 -55q117 0 198 94t81 240q0 108 -48 172.5t-134 64.5q-82 0 -145.5 -47t-97.5 -130t-34 -179z" /> +<glyph unicode=":" horiz-adv-x="551" d="M33 94q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -78 -47.5 -129.5t-124.5 -51.5q-66 0 -97.5 35.5t-31.5 87.5zM205 948q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -79 -48.5 -130t-125.5 -51q-66 0 -96.5 35.5t-30.5 87.5z" /> +<glyph unicode=";" horiz-adv-x="551" d="M-100 -264q95 214 198 502h236l8 -23q-125 -260 -266 -479h-176zM205 948q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -79 -48.5 -130t-125.5 -51q-66 0 -96.5 35.5t-30.5 87.5z" /> +<glyph unicode="&#x3c;" d="M115 651v121l936 488v-195l-697 -344l697 -303v-197z" /> +<glyph unicode="=" d="M117 430v180h936v-180h-936zM117 831v179h936v-179h-936z" /> +<glyph unicode="&#x3e;" d="M115 221v197l694 303l-694 344v195l936 -488v-121z" /> +<glyph unicode="?" horiz-adv-x="907" d="M162 94q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -79 -49 -129t-125 -50q-66 0 -96.5 34.5t-30.5 86.5zM186 1370q207 113 410 113q171 0 269 -85.5t98 -242.5q0 -120 -63.5 -217.5t-231.5 -216.5q-104 -74 -150 -133t-61 -144h-197q18 133 71.5 220.5 t176.5 177.5q107 77 146.5 117t58 80.5t18.5 88.5q0 70 -42.5 114t-123.5 44q-77 0 -150 -27.5t-151 -64.5z" /> +<glyph unicode="@" horiz-adv-x="1743" d="M100 502q0 270 122.5 489t343 344t493.5 125q200 0 346 -74.5t223.5 -214.5t77.5 -325q0 -176 -59.5 -322.5t-166.5 -229.5t-239 -83q-98 0 -150.5 46t-64.5 120h-6q-101 -166 -277 -166q-123 0 -189.5 78.5t-66.5 218.5q0 151 67.5 279.5t188 203t263.5 74.5 q52 0 94.5 -5t79.5 -13t129 -39l-101 -392q-30 -114 -30 -159q0 -92 79 -92q72 0 134 66.5t97.5 174.5t35.5 230q0 228 -128.5 347.5t-363.5 119.5q-214 0 -385 -99.5t-266.5 -281.5t-95.5 -406q0 -259 140.5 -401t391.5 -142q200 0 430 86v-155q-219 -90 -454 -90 q-210 0 -367 83.5t-241.5 239.5t-84.5 365zM676 522q0 -157 112 -157q82 0 141.5 72t100.5 220l64 240q-53 16 -105 16q-86 0 -158.5 -53.5t-113.5 -144t-41 -193.5z" /> +<glyph unicode="A" horiz-adv-x="1210" d="M-121 0l783 1464h274l166 -1464h-234l-41 406h-485l-209 -406h-254zM446 614h365q-40 416 -45.5 503.5t-5.5 139.5q-55 -139 -142 -307z" /> +<glyph unicode="B" horiz-adv-x="1247" d="M70 0l309 1462h399q222 0 335.5 -84t113.5 -248q0 -146 -86.5 -243t-239.5 -127v-8q108 -28 167.5 -103.5t59.5 -183.5q0 -217 -150 -341t-417 -124h-491zM348 201h223q147 0 230.5 68t83.5 194q0 98 -60 149.5t-176 51.5h-200zM489 858h199q139 0 215 60.5t76 171.5 q0 172 -223 172h-181z" /> +<glyph unicode="C" horiz-adv-x="1225" d="M135 545q0 260 105.5 483t281.5 339t402 116q217 0 389 -92l-94 -195q-63 34 -134 58t-161 24q-154 0 -275 -89t-193.5 -259.5t-72.5 -374.5q0 -180 82.5 -275.5t243.5 -95.5q141 0 329 68v-205q-180 -67 -374 -67q-248 0 -388.5 148.5t-140.5 416.5z" /> +<glyph unicode="D" horiz-adv-x="1374" d="M70 0l309 1462h369q271 0 417 -145t146 -424q0 -271 -100 -473t-291 -311t-449 -109h-401zM348 201h135q177 0 309 86t202.5 242t70.5 356q0 184 -88 280.5t-256 96.5h-146z" /> +<glyph unicode="E" horiz-adv-x="1077" d="M70 0l309 1462h776l-43 -205h-539l-84 -395h502l-41 -203h-504l-96 -456h539l-43 -203h-776z" /> +<glyph unicode="F" horiz-adv-x="1026" d="M70 0l309 1462h774l-43 -205h-537l-96 -454h502l-45 -203h-500l-127 -600h-237z" /> +<glyph unicode="G" horiz-adv-x="1399" d="M135 539q0 264 102.5 483t290 340t426.5 121q111 0 213 -20.5t205 -69.5l-90 -203q-174 86 -334 86q-158 0 -287 -90.5t-203.5 -258t-74.5 -372.5q0 -183 89 -277t253 -94q109 0 215 33l80 371h-277l43 205h512l-157 -736q-112 -40 -218.5 -58.5t-238.5 -18.5 q-261 0 -405 146t-144 413z" /> +<glyph unicode="H" horiz-adv-x="1411" d="M70 0l309 1462h237l-127 -598h566l127 598h237l-309 -1462h-238l140 659h-566l-139 -659h-237z" /> +<glyph unicode="I" horiz-adv-x="608" d="M70 0l311 1462h235l-311 -1462h-235z" /> +<glyph unicode="J" horiz-adv-x="612" d="M-322 -383l5 201q84 -21 153 -21q201 0 254 250l299 1415h238l-305 -1446q-46 -217 -161.5 -320.5t-312.5 -103.5q-104 0 -170 25z" /> +<glyph unicode="K" horiz-adv-x="1198" d="M70 0l309 1462h237l-151 -706l141 166l492 540h284l-616 -669l321 -793h-262l-252 655l-149 -100l-117 -555h-237z" /> +<glyph unicode="L" horiz-adv-x="1016" d="M70 0l309 1462h237l-266 -1257h539l-43 -205h-776z" /> +<glyph unicode="M" horiz-adv-x="1757" d="M68 0l309 1462h323l109 -1149h6l606 1149h344l-305 -1462h-227l182 872q39 186 86 342h-6l-643 -1214h-205l-115 1214h-6q-9 -118 -55 -340l-184 -874h-219z" /> +<glyph unicode="N" horiz-adv-x="1491" d="M68 0l309 1462h268l399 -1149h7q6 54 31 192.5t40 203.5l160 753h219l-309 -1462h-260l-410 1163h-6l-10 -69q-24 -149 -35.5 -212.5t-183.5 -881.5h-219z" /> +<glyph unicode="O" horiz-adv-x="1485" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q251 0 390.5 -149t139.5 -414q0 -279 -95 -497t-261.5 -331.5t-386.5 -113.5q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q138 0 248.5 95.5t172 265t61.5 375.5q0 170 -79 265t-223 95 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5z" /> +<glyph unicode="P" horiz-adv-x="1174" d="M70 0l309 1462h334q229 0 345 -100.5t116 -300.5q0 -248 -169.5 -381t-472.5 -133h-110l-115 -547h-237zM465 748h94q178 0 275.5 79.5t97.5 225.5q0 109 -58.5 159t-179.5 50h-119z" /> +<glyph unicode="Q" horiz-adv-x="1485" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q251 0 390.5 -149t139.5 -414q0 -322 -130 -563t-355 -332l264 -375h-289l-202 328h-31q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q138 0 248.5 94t172 263.5t61.5 378.5q0 170 -79 265t-223 95 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5z" /> +<glyph unicode="R" horiz-adv-x="1206" d="M70 0l309 1462h338q223 0 342 -94.5t119 -290.5q0 -165 -86.5 -278.5t-257.5 -165.5l249 -633h-260l-207 584h-186l-123 -584h-237zM473 782h123q170 0 254 75t84 206q0 105 -59 151t-183 46h-119z" /> +<glyph unicode="S" horiz-adv-x="1057" d="M39 55v224q173 -97 350 -97q137 0 216 58.5t79 162.5q0 69 -41 122.5t-172 136.5q-105 67 -155 122t-76.5 120.5t-26.5 144.5q0 128 61.5 227t174 153t253.5 54q205 0 381 -92l-86 -191q-161 78 -295 78q-109 0 -175 -58.5t-66 -152.5q0 -47 15 -82.5t46.5 -66 t134.5 -95.5q155 -97 214 -187.5t59 -207.5q0 -210 -144.5 -329t-398.5 -119q-210 0 -348 75z" /> +<glyph unicode="T" horiz-adv-x="1053" d="M176 1257l45 205h998l-43 -205h-381l-267 -1257h-237l264 1257h-379z" /> +<glyph unicode="U" horiz-adv-x="1399" d="M152 391q0 83 20 170l193 901h237l-192 -905q-21 -88 -21 -158q0 -102 59.5 -158.5t180.5 -56.5q145 0 230 80.5t124 261.5l199 936h237l-202 -956q-56 -267 -208 -396.5t-403 -129.5q-217 0 -335.5 106t-118.5 305z" /> +<glyph unicode="V" horiz-adv-x="1165" d="M186 1462h232l74 -905q9 -103 11 -233l-1 -76h4q70 178 137 309l455 905h254l-764 -1462h-258z" /> +<glyph unicode="W" horiz-adv-x="1788" d="M203 1462h229l19 -850q0 -136 -13 -346h6q83 221 142 355l387 841h225l31 -839l3 -169l-3 -188h8q28 88 70 197.5t61 152.5l358 846h246l-655 -1462h-258l-37 842l-6 185l4 106h-6q-47 -144 -117 -291l-385 -842h-256z" /> +<glyph unicode="X" horiz-adv-x="1151" d="M-111 0l586 770l-250 692h246l178 -540l402 540h266l-551 -710l274 -752h-256l-192 592l-438 -592h-265z" /> +<glyph unicode="Y" horiz-adv-x="1092" d="M186 1462h242l154 -669l432 669h266l-623 -913l-114 -549h-238l119 553z" /> +<glyph unicode="Z" horiz-adv-x="1092" d="M-39 0l33 168l850 1087h-598l43 207h897l-35 -172l-852 -1085h645l-43 -205h-940z" /> +<glyph unicode="[" horiz-adv-x="631" d="M-27 -324l381 1786h430l-39 -176h-221l-303 -1433h221l-39 -177h-430z" /> +<glyph unicode="\" horiz-adv-x="788" d="M221 1462h207l219 -1462h-209z" /> +<glyph unicode="]" horiz-adv-x="631" d="M-143 -324l37 177h219l305 1433h-221l39 176h430l-381 -1786h-428z" /> +<glyph unicode="^" horiz-adv-x="1069" d="M37 537l608 933h127l272 -933h-184l-188 690l-434 -690h-201z" /> +<glyph unicode="_" horiz-adv-x="813" d="M-188 -324l30 140h817l-30 -140h-817z" /> +<glyph unicode="`" horiz-adv-x="1135" d="M541 1548v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="a" horiz-adv-x="1186" d="M94 367q0 202 69.5 378t191.5 278.5t268 102.5q97 0 167 -45.5t109 -132.5h10l62 158h180l-236 -1106h-182l21 176h-6q-158 -196 -349 -196q-141 0 -223 101.5t-82 285.5zM332 373q0 -102 40.5 -152.5t112.5 -50.5q82 0 161 77.5t130 207.5t51 284q0 88 -47 141.5 t-123 53.5q-85 0 -160 -77t-120 -209.5t-45 -274.5z" /> +<glyph unicode="b" horiz-adv-x="1200" d="M47 0l330 1556h235l-71 -333q-13 -63 -38 -156.5t-40 -140.5h8q90 113 165 156.5t161 43.5q145 0 226 -103.5t81 -285.5q0 -202 -69.5 -379.5t-190.5 -277.5t-266 -100q-98 0 -168.5 45t-110.5 131h-10l-64 -156h-178zM369 373q0 -96 46.5 -149.5t131.5 -53.5t159 78.5 t117 210t43 274.5q0 201 -155 201q-81 0 -162 -80t-130.5 -210.5t-49.5 -270.5z" /> +<glyph unicode="c" horiz-adv-x="954" d="M94 389q0 207 73.5 376.5t206.5 265t302 95.5q164 0 297 -61l-70 -184q-122 53 -221 53q-150 0 -250 -153.5t-100 -379.5q0 -111 56 -171t155 -60q74 0 138.5 22t129.5 54v-195q-140 -71 -305 -71q-196 0 -304 106t-108 303z" /> +<glyph unicode="d" horiz-adv-x="1198" d="M94 369q0 205 71.5 383t191.5 276t266 98q179 0 268 -178h8q13 146 37 250l76 358h233l-330 -1556h-184l19 176h-7q-88 -106 -170 -151t-174 -45q-143 0 -224 101.5t-81 287.5zM332 373q0 -203 157 -203q82 0 162.5 82t129 214t48.5 267q0 91 -43.5 146t-132.5 55 q-85 0 -159 -77t-118 -211t-44 -273z" /> +<glyph unicode="e" horiz-adv-x="1075" d="M94 401q0 198 77.5 368.5t210 263.5t296.5 93q161 0 250.5 -72.5t89.5 -205.5q0 -182 -166.5 -284.5t-474.5 -102.5h-43l-2 -31v-29q0 -111 56.5 -174t168.5 -63q72 0 143 19t168 65v-187q-96 -44 -176.5 -62.5t-179.5 -18.5q-197 0 -307.5 111t-110.5 310zM362 633h29 q188 0 294 53.5t106 151.5q0 51 -32 79.5t-95 28.5q-96 0 -180.5 -86t-121.5 -227z" /> +<glyph unicode="f" horiz-adv-x="702" d="M-225 -279q64 -20 114 -20q134 0 177 205l217 1022h-179l21 106l194 76l21 92q44 198 134.5 281.5t256.5 83.5q115 0 211 -43l-61 -176q-74 28 -136 28q-69 0 -110.5 -43t-63.5 -141l-18 -86h229l-37 -178h-229l-223 -1053q-40 -189 -131 -278t-238 -89q-90 0 -149 23 v190z" /> +<glyph unicode="g" horiz-adv-x="1067" d="M-121 -211q0 103 69.5 178t223.5 127q-76 45 -76 127q0 69 46.5 119.5t146.5 97.5q-135 81 -135 252q0 196 122.5 316t323.5 120q80 0 160 -20h383l-31 -137l-192 -33q28 -58 28 -137q0 -193 -119 -306.5t-319 -113.5q-52 0 -92 8q-111 -40 -111 -104q0 -38 31.5 -52 t91.5 -22l127 -16q176 -22 252 -87.5t76 -187.5q0 -196 -151 -303t-429 -107q-203 0 -314.5 75t-111.5 206zM92 -184q0 -65 55.5 -103.5t169.5 -38.5q163 0 255 54t92 155q0 51 -45 80t-158 41l-137 14q-112 -18 -172 -71t-60 -131zM377 680q0 -71 35.5 -109.5t101.5 -38.5 q65 0 112.5 39t74 107t26.5 149q0 142 -133 142q-65 0 -114 -38.5t-76 -105t-27 -145.5z" /> +<glyph unicode="h" horiz-adv-x="1208" d="M47 0l330 1556h235l-57 -262q-27 -126 -73 -293l-19 -75h8q84 106 168.5 153t177.5 47q136 0 208.5 -77.5t72.5 -221.5q0 -76 -23 -174l-139 -653h-234l142 672q18 90 18 127q0 135 -129 135q-112 0 -209.5 -125t-142.5 -342l-98 -467h-236z" /> +<glyph unicode="i" horiz-adv-x="563" d="M47 0l236 1106h235l-235 -1106h-236zM330 1378q0 68 39 110t110 42q53 0 86 -26.5t33 -80.5q0 -71 -40 -112t-105 -41q-53 0 -88 26t-35 82z" /> +<glyph unicode="j" horiz-adv-x="563" d="M-262 -279q64 -20 117 -20q131 0 170 186l260 1219h233l-266 -1247q-38 -181 -127.5 -266t-237.5 -85q-90 0 -149 23v190zM332 1378q0 68 38 110t109 42q54 0 86.5 -26.5t32.5 -80.5q0 -71 -40 -112t-105 -41q-53 0 -87 25.5t-34 82.5z" /> +<glyph unicode="k" horiz-adv-x="1081" d="M47 0l330 1556h235q-135 -627 -159.5 -729.5t-59.5 -226.5h4l490 506h272l-483 -485l291 -621h-262l-209 471l-136 -96l-77 -375h-236z" /> +<glyph unicode="l" horiz-adv-x="563" d="M47 0l330 1556h235l-331 -1556h-234z" /> +<glyph unicode="m" horiz-adv-x="1819" d="M47 0l236 1106h184l-21 -205h9q148 225 352 225q220 0 254 -235h8q75 116 170.5 175.5t198.5 59.5q133 0 202.5 -76.5t69.5 -215.5q0 -64 -22 -181l-140 -653h-235l143 672q19 95 19 133q0 129 -121 129q-108 0 -201.5 -124t-136.5 -329l-101 -481h-235l143 672 q17 82 17 127q0 135 -117 135q-110 0 -203.5 -127t-138.5 -338l-98 -469h-236z" /> +<glyph unicode="n" horiz-adv-x="1208" d="M47 0l236 1106h184l-21 -205h9q83 118 171 171.5t191 53.5q134 0 207.5 -76t73.5 -216q0 -69 -23 -181l-137 -653h-236l142 672q18 90 18 131q0 131 -129 131q-72 0 -142 -57t-126 -164.5t-84 -243.5l-98 -469h-236z" /> +<glyph unicode="o" horiz-adv-x="1174" d="M94 408q0 199 71.5 365t200.5 258.5t298 92.5q195 0 305 -116t110 -316q0 -202 -73 -367.5t-200.5 -254t-293.5 -88.5q-192 0 -305 114.5t-113 311.5zM332 403q0 -111 49.5 -170t146.5 -59q90 0 162 68t112 190.5t40 269.5q0 107 -49 167.5t-140 60.5q-93 0 -166.5 -71.5 t-114 -194t-40.5 -261.5z" /> +<glyph unicode="p" horiz-adv-x="1200" d="M-55 -492l338 1598h184l-21 -188h9q157 208 344 208q143 0 224 -103t81 -286q0 -204 -70 -381.5t-190.5 -276.5t-265.5 -99q-181 0 -269 176h-10q-7 -97 -25 -185l-96 -463h-233zM369 373q0 -96 46.5 -149.5t131.5 -53.5t159 78.5t117 210t43 274.5q0 201 -155 201 q-81 0 -161 -79.5t-130.5 -210.5t-50.5 -271z" /> +<glyph unicode="q" horiz-adv-x="1198" d="M94 367q0 208 73 387t192.5 275.5t265.5 96.5q183 0 274 -178h10l64 158h178l-340 -1598h-233l75 349q12 56 43.5 180t38.5 141h-8q-84 -108 -164 -153t-170 -45q-139 0 -219 102.5t-80 284.5zM332 373q0 -203 160 -203q80 0 159 81t127.5 213t48.5 269q0 94 -45.5 147.5 t-126.5 53.5q-86 0 -160 -77.5t-118.5 -209.5t-44.5 -274z" /> +<glyph unicode="r" horiz-adv-x="836" d="M47 0l236 1106h184l-21 -205h9q83 120 166 172.5t176 52.5q62 0 108 -12l-51 -219q-54 14 -102 14q-126 0 -225 -113t-138 -296l-106 -500h-236z" /> +<glyph unicode="s" horiz-adv-x="922" d="M14 47v203q153 -90 312 -90q97 0 157 40t60 109q0 51 -34.5 87.5t-141.5 97.5q-125 67 -176.5 136.5t-51.5 164.5q0 155 107 243t289 88q196 0 346 -84l-76 -176q-140 76 -266 76q-73 0 -118.5 -33t-45.5 -92q0 -45 33 -80t135 -90q105 -59 149 -101t67 -91.5t23 -114.5 q0 -173 -118 -266.5t-328 -93.5q-190 0 -322 67z" /> +<glyph unicode="t" horiz-adv-x="752" d="M92 928l21 110l190 82l129 232h146l-52 -246h279l-39 -178h-277l-122 -572q-13 -55 -13 -92q0 -43 25 -68.5t76 -25.5q68 0 151 31v-178q-35 -17 -95 -30t-120 -13q-274 0 -274 247q0 57 16 131l121 570h-162z" /> +<glyph unicode="u" horiz-adv-x="1208" d="M111 274q0 63 12 124.5t24 123.5l123 584h236l-129 -610q-31 -141 -31 -193q0 -133 127 -133q72 0 143 57t126 162.5t85 247.5l99 469h233l-233 -1106h-185l21 205h-8q-82 -116 -171 -170.5t-192 -54.5q-134 0 -207 76t-73 218z" /> +<glyph unicode="v" horiz-adv-x="997" d="M100 1106h232l55 -598q14 -159 14 -297h7q28 74 70 165t65 132l311 598h250l-598 -1106h-275z" /> +<glyph unicode="w" horiz-adv-x="1540" d="M121 1106h221l13 -646q-2 -87 -11 -245h6q66 176 109 272l278 619h254l19 -604l1 -53l-3 -234h6q17 50 57 158.5t63.5 163.5t251.5 569h244l-518 -1106h-268l-19 627l-1 70l3 200q-25 -62 -51.5 -125t-345.5 -772h-262z" /> +<glyph unicode="x" horiz-adv-x="1032" d="M-86 0l475 569l-231 537h245l144 -373l287 373h274l-461 -549l248 -557h-246l-160 387l-305 -387h-270z" /> +<glyph unicode="y" horiz-adv-x="1004" d="M-170 -285q75 -16 125 -16q74 0 134 43.5t124 155.5l51 92l-164 1116h232l63 -531q9 -62 16 -174.5t7 -181.5h6q86 215 135 313l293 574h254l-688 -1280q-90 -165 -196 -241.5t-249 -76.5q-76 0 -143 19v188z" /> +<glyph unicode="z" horiz-adv-x="920" d="M-39 0l29 147l635 781h-439l39 178h705l-37 -170l-623 -758h486l-37 -178h-758z" /> +<glyph unicode="{" horiz-adv-x="721" d="M8 485l39 187q120 0 191.5 42.5t93.5 143.5l59 275q28 134 73 201.5t120 97.5t198 30h60l-41 -184q-96 0 -139.5 -34t-61.5 -116l-70 -309q-24 -108 -87 -170.5t-179 -79.5v-6q160 -45 160 -215q0 -38 -16 -121l-43 -194q-11 -48 -11 -74q0 -51 32.5 -74.5t109.5 -23.5 v-185h-39q-316 0 -316 236q0 61 17 133l45 201q14 65 14 98q0 141 -209 141z" /> +<glyph unicode="|" d="M498 -481v2033h178v-2033h-178z" /> +<glyph unicode="}" horiz-adv-x="721" d="M-88 -141q106 2 152.5 36.5t64.5 114.5l70 309q24 109 87 170t179 78v6q-158 48 -158 215q0 55 17 121l43 197q10 44 10 74q0 58 -43 78t-121 20l35 184h22q318 0 318 -235q0 -61 -17 -133l-45 -203q-14 -65 -14 -98q0 -142 209 -142l-39 -186q-121 0 -192 -42t-93 -142 l-63 -306q-34 -165 -123.5 -232t-269.5 -67h-29v183z" /> +<glyph unicode="~" d="M111 571v191q100 108 249 108q64 0 118.5 -12t146.5 -51q70 -30 115 -42.5t94 -12.5q50 0 112.5 31t120.5 89v-190q-103 -111 -250 -111q-63 0 -124 16.5t-138 49.5q-76 32 -119.5 43.5t-91.5 11.5q-51 0 -112 -31t-121 -90z" /> +<glyph unicode="&#xa1;" horiz-adv-x="557" d="M-45 -373l266 1018h174l-166 -1018h-274zM221 936q0 82 49 132t127 50q65 0 95 -35.5t30 -89.5q0 -80 -47 -130t-127 -50q-59 0 -93 31.5t-34 91.5z" /> +<glyph unicode="&#xa2;" d="M195 586q0 190 63.5 351t178 260.5t261.5 121.5l35 164h156l-37 -164q124 -12 221 -57l-69 -185q-125 53 -222 53q-99 0 -180 -71.5t-125.5 -194.5t-44.5 -266q0 -111 56 -171t155 -60q74 0 138.5 21.5t129.5 53.5v-194q-133 -69 -293 -74l-40 -194h-156l45 213 q-132 34 -202 134.5t-70 258.5z" /> +<glyph unicode="&#xa3;" d="M-18 0l38 193q200 45 250 276l35 164h-196l36 172h197l61 299q38 185 153 282t300 97q188 0 352 -86l-88 -183q-143 74 -258 74q-185 0 -227 -205l-57 -278h333l-34 -172h-336l-33 -152q-21 -98 -68.5 -165t-130.5 -109h690l-45 -207h-972z" /> +<glyph unicode="&#xa4;" d="M141 1057l119 119l127 -127q102 61 207 61q108 0 207 -63l127 129l121 -117l-129 -129q61 -99 61 -207q0 -114 -61 -209l127 -125l-119 -119l-127 127q-95 -59 -207 -59q-120 0 -207 59l-127 -125l-117 119l127 125q-61 95 -61 207q0 110 61 205zM377 723 q0 -91 62.5 -154t154.5 -63q91 0 156 62t65 155t-65 156t-156 63q-92 0 -154.5 -64t-62.5 -155z" /> +<glyph unicode="&#xa5;" d="M106 244l33 155h273l30 148h-272l35 155h211l-199 760h232l145 -669l432 669h248l-518 -760h217l-35 -155h-274l-31 -148h274l-33 -155h-272l-53 -244h-221l51 244h-273z" /> +<glyph unicode="&#xa6;" d="M498 315h178v-796h-178v796zM498 758v794h178v-794h-178z" /> +<glyph unicode="&#xa7;" horiz-adv-x="995" d="M39 53v187q152 -93 319 -93q116 0 174 40.5t58 111.5q0 43 -39 79.5t-141 84.5q-130 60 -189 131.5t-59 169.5q0 188 219 307q-47 32 -78 82t-31 115q0 138 111.5 220.5t296.5 82.5q178 0 332 -78l-68 -158q-62 29 -129.5 50.5t-144.5 21.5q-86 0 -134.5 -34.5 t-48.5 -94.5q0 -43 36.5 -76.5t148.5 -83.5q127 -56 186.5 -127.5t59.5 -167.5q0 -92 -52.5 -171t-160.5 -140q102 -76 102 -193q0 -157 -123 -245t-330 -88q-188 0 -315 67zM358 793q0 -61 46.5 -104.5t173.5 -100.5q62 36 99.5 90.5t37.5 114.5t-49.5 104.5t-155.5 89.5 q-69 -26 -110.5 -79t-41.5 -115z" /> +<glyph unicode="&#xa8;" horiz-adv-x="1135" d="M426 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM809 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="&#xa9;" horiz-adv-x="1704" d="M131 731q0 200 100 375t275 276t377 101q199 0 373.5 -99t276 -275.5t101.5 -377.5q0 -199 -98.5 -373t-272.5 -276t-380 -102q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM254 731q0 -168 83 -312.5t229 -230.5t317 -86q173 0 319.5 87t227.5 231.5t81 310.5 q0 165 -82 310.5t-227.5 232t-318.5 86.5q-168 0 -314.5 -84.5t-230.5 -231t-84 -313.5zM502 727q0 216 113.5 340.5t312.5 124.5q138 0 266 -66l-68 -147q-106 55 -196 55q-113 0 -175.5 -76t-62.5 -231q0 -301 238 -301q47 0 112 16t109 35v-158q-117 -51 -240 -51 q-197 0 -303 123.5t-106 335.5z" /> +<glyph unicode="&#xaa;" horiz-adv-x="729" d="M160 1016q0 128 47 238.5t122.5 167.5t168.5 57q113 0 166 -103h6l39 90h118l-147 -684h-123l10 105h-4q-50 -62 -98 -89.5t-109 -27.5q-91 0 -143.5 66t-52.5 180zM319 1022q0 -125 93 -125q50 0 97.5 48t77 127.5t29.5 158.5q0 119 -102 119q-82 0 -138.5 -97.5 t-56.5 -230.5z" /> +<glyph unicode="&#xab;" horiz-adv-x="1055" d="M80 553v22l395 420l135 -118l-288 -332l153 -369l-178 -76zM520 530v25l385 434l137 -112l-280 -351l147 -350l-180 -76z" /> +<glyph unicode="&#xac;" d="M117 631v180h936v-555h-179v375h-757z" /> +<glyph unicode="&#xad;" horiz-adv-x="649" d="M47 446l45 203h502l-45 -203h-502z" /> +<glyph unicode="&#xae;" horiz-adv-x="1704" d="M131 731q0 200 100 375t275 276t377 101q199 0 373.5 -99t276 -275.5t101.5 -377.5q0 -199 -98.5 -373t-272.5 -276t-380 -102q-207 0 -382 103.5t-272.5 276.5t-97.5 371zM254 731q0 -168 83 -312.5t229 -230.5t317 -86q173 0 319.5 87t227.5 231.5t81 310.5 q0 165 -82 310.5t-227.5 232t-318.5 86.5q-168 0 -314.5 -84.5t-230.5 -231t-84 -313.5zM608 291v878h269q337 0 337 -262q0 -83 -45.5 -145t-130.5 -98l211 -373h-200l-172 325h-91v-325h-178zM786 760h72q84 0 129 36t45 99q0 73 -45.5 101t-128.5 28h-72v-264z" /> +<glyph unicode="&#xaf;" horiz-adv-x="903" d="M111 1556l39 166h911l-41 -166h-909z" /> +<glyph unicode="&#xb0;" horiz-adv-x="877" d="M188 1153q0 136 97 233t233 97t232 -97t96 -233q0 -137 -96 -231.5t-232 -94.5q-88 0 -165 44t-121 119t-44 163zM340 1153q0 -70 52 -122t126 -52q72 0 124 52t52 122q0 74 -51.5 126t-124.5 52q-74 0 -126 -51.5t-52 -126.5z" /> +<glyph unicode="&#xb1;" d="M117 0v180h936v-180h-936zM117 657v181h379v381h180v-381h377v-181h-377v-374h-180v374h-379z" /> +<glyph unicode="&#xb2;" horiz-adv-x="745" d="M78 586l28 135l269 223q111 95 148.5 136t55 77t17.5 74q0 46 -28 72t-76 26q-91 0 -191 -80l-80 123q68 54 142.5 81.5t168.5 27.5q115 0 183.5 -60t68.5 -155q0 -69 -23.5 -124.5t-74 -110.5t-168.5 -146l-174 -142h371l-33 -157h-604z" /> +<glyph unicode="&#xb3;" horiz-adv-x="745" d="M104 625v159q126 -71 248 -71q90 0 139.5 37t49.5 106q0 113 -146 113h-108l28 133h93q89 0 142.5 34t53.5 99q0 100 -117 100q-92 0 -188 -65l-68 121q126 90 291 90q124 0 193 -55.5t69 -153.5q0 -90 -54.5 -149t-158.5 -85v-4q78 -18 115 -67t37 -115 q0 -129 -99.5 -206t-269.5 -77q-138 0 -250 56z" /> +<glyph unicode="&#xb4;" horiz-adv-x="1135" d="M508 1241v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="&#xb5;" horiz-adv-x="1221" d="M-55 -492l338 1598h235l-141 -670q-19 -84 -19 -129q0 -65 33 -101t96 -36q113 0 209.5 125.5t141.5 337.5l102 473h231l-235 -1106h-184l22 190h-10q-75 -111 -153 -160.5t-165 -49.5q-108 0 -155 81h-8q-9 -73 -39 -235l-66 -318h-233z" /> +<glyph unicode="&#xb6;" horiz-adv-x="1341" d="M172 1042q0 260 109 387t342 127h581v-1816h-139v1638h-188v-1638h-140v819q-62 -18 -145 -18q-216 0 -318 125t-102 376z" /> +<glyph unicode="&#xb7;" horiz-adv-x="551" d="M150 692q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -78 -47.5 -129.5t-124.5 -51.5q-66 0 -97.5 35.5t-31.5 87.5z" /> +<glyph unicode="&#xb8;" horiz-adv-x="420" d="M-188 -342q47 -14 96 -14q137 0 137 96q0 40 -35 61.5t-104 30.5l98 168h146l-50 -96q72 -25 104 -67t32 -101q0 -106 -82 -167t-224 -61q-64 0 -118 15v135z" /> +<glyph unicode="&#xb9;" horiz-adv-x="745" d="M193 1247l339 215h162l-186 -876h-191l99 461q17 79 57 217q-21 -20 -49.5 -43t-153.5 -103z" /> +<glyph unicode="&#xba;" horiz-adv-x="721" d="M164 1047q0 122 44 221.5t125.5 155t188.5 55.5q124 0 189 -71.5t65 -201.5q0 -126 -42 -225t-121 -155t-189 -56q-122 0 -191 73t-69 204zM326 1042q0 -141 112 -141q77 0 127.5 87.5t50.5 219.5q0 138 -106 138q-81 0 -132.5 -87.5t-51.5 -216.5z" /> +<glyph unicode="&#xbb;" horiz-adv-x="1055" d="M10 211l281 348l-146 352l179 76l211 -432v-25l-385 -432zM444 211l287 330l-153 370l180 76l217 -455v-22l-397 -418z" /> +<glyph unicode="&#xbc;" horiz-adv-x="1661" d="M149 0l1085 1462h195l-1083 -1462h-197zM151 1247l339 215h162l-186 -876h-191l99 461q17 79 57 217q-21 -20 -49.5 -43t-153.5 -103zM775 177l26 137l477 569h197l-121 -563h123l-29 -143h-122l-39 -176h-183l39 176h-368zM973 320h199l52 221l34 129q-32 -51 -98 -131z " /> +<glyph unicode="&#xbd;" horiz-adv-x="1661" d="M121 0l1085 1462h195l-1083 -1462h-197zM122 1247l339 215h162l-186 -876h-191l99 461q17 79 57 217q-21 -20 -49.5 -43t-153.5 -103zM860 1l28 135l269 223q111 95 148.5 136t55 77t17.5 74q0 46 -28 72t-76 26q-91 0 -191 -80l-80 123q68 54 142.5 81.5t168.5 27.5 q115 0 183.5 -60t68.5 -155q0 -69 -23.5 -124.5t-74 -110.5t-168.5 -146l-174 -142h371l-33 -157h-604z" /> +<glyph unicode="&#xbe;" horiz-adv-x="1683" d="M291 0l1085 1462h195l-1083 -1462h-197zM881 177l26 137l477 569h197l-121 -563h123l-29 -143h-122l-39 -176h-183l39 176h-368zM1079 320h199l52 221l34 129q-32 -51 -98 -131zM108 625v159q126 -71 248 -71q90 0 139.5 37t49.5 106q0 113 -146 113h-108l28 133h93 q89 0 142.5 34t53.5 99q0 100 -117 100q-92 0 -188 -65l-68 121q126 90 291 90q124 0 193 -55.5t69 -153.5q0 -90 -54.5 -149t-158.5 -85v-4q78 -18 115 -67t37 -115q0 -129 -99.5 -206t-269.5 -77q-138 0 -250 56z" /> +<glyph unicode="&#xbf;" horiz-adv-x="907" d="M-35 -68q0 120 64 219t231 216q93 64 141 122.5t70 153.5h197q-25 -146 -79.5 -231t-170.5 -168q-107 -79 -145.5 -118t-57 -79t-18.5 -88q0 -71 42 -114.5t123 -43.5q76 0 149.5 27.5t152.5 65.5l75 -177q-205 -112 -409 -112q-174 0 -269.5 85.5t-95.5 241.5zM465 934 q0 78 46.5 129t125.5 51q66 0 97.5 -34t31.5 -87q0 -85 -48 -134.5t-130 -49.5q-56 0 -89.5 32.5t-33.5 92.5z" /> +<glyph unicode="&#xc0;" horiz-adv-x="1210" d="M-121 0l783 1464h274l166 -1464h-234l-41 406h-485l-209 -406h-254zM446 614h365q-40 416 -45.5 503.5t-5.5 139.5q-55 -139 -142 -307zM538 1886v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="&#xc1;" horiz-adv-x="1210" d="M-121 0l783 1464h274l166 -1464h-234l-41 406h-485l-209 -406h-254zM446 614h365q-40 416 -45.5 503.5t-5.5 139.5q-55 -139 -142 -307zM707 1579v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="&#xc2;" horiz-adv-x="1210" d="M-121 0l783 1464h274l166 -1464h-234l-41 406h-485l-209 -406h-254zM446 614h365q-40 416 -45.5 503.5t-5.5 139.5q-55 -139 -142 -307zM444 1579v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="&#xc3;" horiz-adv-x="1210" d="M-121 0l783 1464h274l166 -1464h-234l-41 406h-485l-209 -406h-254zM446 614h365q-40 416 -45.5 503.5t-5.5 139.5q-55 -139 -142 -307zM441 1577q57 285 256 285q46 0 85 -17.5t72.5 -38t63.5 -38t59 -17.5q40 0 65 26.5t48 86.5h137q-66 -285 -260 -285q-45 0 -82.5 17 t-71.5 37.5t-65.5 37.5t-63.5 17q-38 0 -63 -27.5t-43 -83.5h-137z" /> +<glyph unicode="&#xc4;" horiz-adv-x="1210" d="M-121 0l783 1464h274l166 -1464h-234l-41 406h-485l-209 -406h-254zM446 614h365q-40 416 -45.5 503.5t-5.5 139.5q-55 -139 -142 -307zM518 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM901 1718 q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="&#xc5;" horiz-adv-x="1210" d="M-121 0l783 1464h274l166 -1464h-234l-41 406h-485l-209 -406h-254zM446 614h365q-40 416 -45.5 503.5t-5.5 139.5q-55 -139 -142 -307zM568 1573q0 103 65 164.5t168 61.5q104 0 171 -60.5t67 -163.5q0 -104 -66 -165.5t-172 -61.5t-169.5 61t-63.5 164zM697 1573 q0 -49 26.5 -76.5t77.5 -27.5q47 0 77 27.5t30 76.5q0 50 -30 78.5t-77 28.5q-45 0 -74.5 -28.5t-29.5 -78.5z" /> +<glyph unicode="&#xc6;" horiz-adv-x="1753" d="M-121 0l930 1462h1020l-43 -205h-539l-84 -395h504l-43 -200h-502l-98 -459h539l-43 -203h-777l86 406h-432l-256 -406h-262zM528 614h344l138 643h-82z" /> +<glyph unicode="&#xc7;" horiz-adv-x="1225" d="M135 545q0 260 105.5 483t281.5 339t402 116q217 0 389 -92l-94 -195q-63 34 -134 58t-161 24q-154 0 -275 -89t-193.5 -259.5t-72.5 -374.5q0 -180 82.5 -275.5t243.5 -95.5q141 0 329 68v-205q-180 -67 -374 -67q-248 0 -388.5 148.5t-140.5 416.5zM367 -342 q47 -14 96 -14q137 0 137 96q0 40 -35 61.5t-104 30.5l98 168h146l-50 -96q72 -25 104 -67t32 -101q0 -106 -82 -167t-224 -61q-64 0 -118 15v135z" /> +<glyph unicode="&#xc8;" horiz-adv-x="1077" d="M70 0l309 1462h776l-43 -205h-539l-84 -395h502l-41 -203h-504l-96 -456h539l-43 -203h-776zM526 1886v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="&#xc9;" horiz-adv-x="1077" d="M70 0l309 1462h776l-43 -205h-539l-84 -395h502l-41 -203h-504l-96 -456h539l-43 -203h-776zM633 1579v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="&#xca;" horiz-adv-x="1077" d="M70 0l309 1462h776l-43 -205h-539l-84 -395h502l-41 -203h-504l-96 -456h539l-43 -203h-776zM417 1579v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="&#xcb;" horiz-adv-x="1077" d="M70 0l309 1462h776l-43 -205h-539l-84 -395h502l-41 -203h-504l-96 -456h539l-43 -203h-776zM479 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM862 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5 q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="&#xcc;" horiz-adv-x="608" d="M70 0l311 1462h235l-311 -1462h-235zM253 1886v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="&#xcd;" horiz-adv-x="608" d="M70 0l311 1462h235l-311 -1462h-235zM415 1579v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="&#xce;" horiz-adv-x="608" d="M70 0l311 1462h235l-311 -1462h-235zM160 1579v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="&#xcf;" horiz-adv-x="608" d="M70 0l311 1462h235l-311 -1462h-235zM243 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM626 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="&#xd0;" horiz-adv-x="1374" d="M53 623l45 200h144l137 639h369q271 0 417 -145t146 -424q0 -271 -100 -473t-291 -311t-449 -109h-401l129 623h-146zM348 201h135q177 0 309 86t202.5 242t70.5 356q0 184 -88 280.5t-256 96.5h-146l-94 -439h285l-45 -200h-283z" /> +<glyph unicode="&#xd1;" horiz-adv-x="1491" d="M68 0l309 1462h268l399 -1149h7q6 54 31 192.5t40 203.5l160 753h219l-309 -1462h-260l-410 1163h-6l-10 -69q-24 -149 -35.5 -212.5t-183.5 -881.5h-219zM582 1577q57 285 256 285q46 0 85 -17.5t72.5 -38t63.5 -38t59 -17.5q40 0 65 26.5t48 86.5h137 q-66 -285 -260 -285q-45 0 -82.5 17t-71.5 37.5t-65.5 37.5t-63.5 17q-38 0 -63 -27.5t-43 -83.5h-137z" /> +<glyph unicode="&#xd2;" horiz-adv-x="1485" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q251 0 390.5 -149t139.5 -414q0 -279 -95 -497t-261.5 -331.5t-386.5 -113.5q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q138 0 248.5 95.5t172 265t61.5 375.5q0 170 -79 265t-223 95 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5zM652 1886v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="&#xd3;" horiz-adv-x="1485" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q251 0 390.5 -149t139.5 -414q0 -279 -95 -497t-261.5 -331.5t-386.5 -113.5q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q138 0 248.5 95.5t172 265t61.5 375.5q0 170 -79 265t-223 95 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5zM787 1579v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="&#xd4;" horiz-adv-x="1485" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q251 0 390.5 -149t139.5 -414q0 -279 -95 -497t-261.5 -331.5t-386.5 -113.5q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q138 0 248.5 95.5t172 265t61.5 375.5q0 170 -79 265t-223 95 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5zM555 1579v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="&#xd5;" horiz-adv-x="1485" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q251 0 390.5 -149t139.5 -414q0 -279 -95 -497t-261.5 -331.5t-386.5 -113.5q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q138 0 248.5 95.5t172 265t61.5 375.5q0 170 -79 265t-223 95 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5zM543 1577q57 285 256 285q46 0 85 -17.5t72.5 -38t63.5 -38t59 -17.5q40 0 65 26.5t48 86.5h137q-66 -285 -260 -285q-45 0 -82.5 17t-71.5 37.5t-65.5 37.5t-63.5 17q-38 0 -63 -27.5t-43 -83.5h-137z" /> +<glyph unicode="&#xd6;" horiz-adv-x="1485" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q251 0 390.5 -149t139.5 -414q0 -279 -95 -497t-261.5 -331.5t-386.5 -113.5q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q138 0 248.5 95.5t172 265t61.5 375.5q0 170 -79 265t-223 95 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5zM623 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM1006 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5 z" /> +<glyph unicode="&#xd7;" d="M147 1034l125 125l312 -309l313 309l127 -123l-315 -313l311 -313l-123 -123l-313 309l-312 -307l-122 123l307 311z" /> +<glyph unicode="&#xd8;" horiz-adv-x="1485" d="M109 18l129 160q-103 138 -103 365q0 267 98.5 487.5t269.5 337.5t388 117q189 0 317 -94l119 149l133 -104l-133 -166q94 -130 94 -348q0 -279 -95 -497t-261.5 -331.5t-386.5 -113.5q-193 0 -318 83l-118 -149zM377 545q0 -88 24 -164l668 836q-80 65 -197 65 q-141 0 -253 -93t-177 -265t-65 -379zM500 238q75 -56 194 -56q139 0 250.5 95.5t173.5 264.5t62 378q0 88 -19 143z" /> +<glyph unicode="&#xd9;" horiz-adv-x="1399" d="M152 391q0 83 20 170l193 901h237l-192 -905q-21 -88 -21 -158q0 -102 59.5 -158.5t180.5 -56.5q145 0 230 80.5t124 261.5l199 936h237l-202 -956q-56 -267 -208 -396.5t-403 -129.5q-217 0 -335.5 106t-118.5 305zM619 1886v21h245q47 -154 132 -303v-25h-144 q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="&#xda;" horiz-adv-x="1399" d="M152 391q0 83 20 170l193 901h237l-192 -905q-21 -88 -21 -158q0 -102 59.5 -158.5t180.5 -56.5q145 0 230 80.5t124 261.5l199 936h237l-202 -956q-56 -267 -208 -396.5t-403 -129.5q-217 0 -335.5 106t-118.5 305zM791 1579v25q97 108 225 303h264v-19 q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="&#xdb;" horiz-adv-x="1399" d="M152 391q0 83 20 170l193 901h237l-192 -905q-21 -88 -21 -158q0 -102 59.5 -158.5t180.5 -56.5q145 0 230 80.5t124 261.5l199 936h237l-202 -956q-56 -267 -208 -396.5t-403 -129.5q-217 0 -335.5 106t-118.5 305zM536 1579v25q138 128 201 195.5t90 107.5h248 q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="&#xdc;" horiz-adv-x="1399" d="M152 391q0 83 20 170l193 901h237l-192 -905q-21 -88 -21 -158q0 -102 59.5 -158.5t180.5 -56.5q145 0 230 80.5t124 261.5l199 936h237l-202 -956q-56 -267 -208 -396.5t-403 -129.5q-217 0 -335.5 106t-118.5 305zM602 1718q0 60 35 98t98 38q48 0 76.5 -23.5 t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM985 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="&#xdd;" horiz-adv-x="1092" d="M186 1462h242l154 -669l432 669h266l-623 -913l-114 -549h-238l119 553zM610 1579v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="&#xde;" horiz-adv-x="1174" d="M70 0l309 1462h237l-51 -243h97q227 0 344.5 -101t117.5 -301q0 -243 -166.5 -377.5t-476.5 -134.5h-108l-66 -305h-237zM414 506h96q176 0 274.5 78.5t98.5 226.5q0 109 -59.5 158t-180.5 49h-121z" /> +<glyph unicode="&#xdf;" horiz-adv-x="1266" d="M-258 -276q61 -21 113 -21q65 0 106.5 43.5t63.5 147.5l262 1234q48 231 173 333t349 102q188 0 292.5 -80t104.5 -215q0 -169 -179 -299q-118 -87 -148.5 -119.5t-30.5 -67.5q0 -44 74 -101q107 -84 143 -127t55 -92.5t19 -109.5q0 -172 -116 -272t-314 -100 q-182 0 -283 65v201q126 -86 252 -86q105 0 164 44t59 124q0 48 -23.5 85t-111.5 107q-82 64 -121 121.5t-39 126.5q0 75 44.5 139t135.5 124q98 66 138.5 112t40.5 98q0 65 -47 101t-132 36q-210 0 -262 -239l-264 -1260q-42 -197 -134.5 -284t-242.5 -87q-69 0 -141 23 v193z" /> +<glyph unicode="&#xe0;" horiz-adv-x="1186" d="M94 367q0 202 69.5 378t191.5 278.5t268 102.5q97 0 167 -45.5t109 -132.5h10l62 158h180l-236 -1106h-182l21 176h-6q-158 -196 -349 -196q-141 0 -223 101.5t-82 285.5zM332 373q0 -102 40.5 -152.5t112.5 -50.5q82 0 161 77.5t130 207.5t51 284q0 88 -47 141.5 t-123 53.5q-85 0 -160 -77t-120 -209.5t-45 -274.5zM470 1548v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="&#xe1;" horiz-adv-x="1186" d="M94 367q0 202 69.5 378t191.5 278.5t268 102.5q97 0 167 -45.5t109 -132.5h10l62 158h180l-236 -1106h-182l21 176h-6q-158 -196 -349 -196q-141 0 -223 101.5t-82 285.5zM332 373q0 -102 40.5 -152.5t112.5 -50.5q82 0 161 77.5t130 207.5t51 284q0 88 -47 141.5 t-123 53.5q-85 0 -160 -77t-120 -209.5t-45 -274.5zM598 1241v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="&#xe2;" horiz-adv-x="1186" d="M94 367q0 202 69.5 378t191.5 278.5t268 102.5q97 0 167 -45.5t109 -132.5h10l62 158h180l-236 -1106h-182l21 176h-6q-158 -196 -349 -196q-141 0 -223 101.5t-82 285.5zM332 373q0 -102 40.5 -152.5t112.5 -50.5q82 0 161 77.5t130 207.5t51 284q0 88 -47 141.5 t-123 53.5q-85 0 -160 -77t-120 -209.5t-45 -274.5zM351 1241v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="&#xe3;" horiz-adv-x="1186" d="M94 367q0 202 69.5 378t191.5 278.5t268 102.5q97 0 167 -45.5t109 -132.5h10l62 158h180l-236 -1106h-182l21 176h-6q-158 -196 -349 -196q-141 0 -223 101.5t-82 285.5zM332 373q0 -102 40.5 -152.5t112.5 -50.5q82 0 161 77.5t130 207.5t51 284q0 88 -47 141.5 t-123 53.5q-85 0 -160 -77t-120 -209.5t-45 -274.5zM344 1239q57 285 256 285q46 0 85 -17.5t72.5 -38t63.5 -38t59 -17.5q40 0 65 26.5t48 86.5h137q-66 -285 -260 -285q-45 0 -82.5 17t-71.5 37.5t-65.5 37.5t-63.5 17q-38 0 -63 -27.5t-43 -83.5h-137z" /> +<glyph unicode="&#xe4;" horiz-adv-x="1186" d="M94 367q0 202 69.5 378t191.5 278.5t268 102.5q97 0 167 -45.5t109 -132.5h10l62 158h180l-236 -1106h-182l21 176h-6q-158 -196 -349 -196q-141 0 -223 101.5t-82 285.5zM332 373q0 -102 40.5 -152.5t112.5 -50.5q82 0 161 77.5t130 207.5t51 284q0 88 -47 141.5 t-123 53.5q-85 0 -160 -77t-120 -209.5t-45 -274.5zM425 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM808 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5 t-31 74.5z" /> +<glyph unicode="&#xe5;" horiz-adv-x="1186" d="M94 367q0 202 69.5 378t191.5 278.5t268 102.5q97 0 167 -45.5t109 -132.5h10l62 158h180l-236 -1106h-182l21 176h-6q-158 -196 -349 -196q-141 0 -223 101.5t-82 285.5zM332 373q0 -102 40.5 -152.5t112.5 -50.5q82 0 161 77.5t130 207.5t51 284q0 88 -47 141.5 t-123 53.5q-85 0 -160 -77t-120 -209.5t-45 -274.5zM517 1464q0 103 65 164.5t168 61.5q104 0 171 -60.5t67 -163.5q0 -104 -66 -165.5t-172 -61.5t-169.5 61t-63.5 164zM646 1464q0 -49 26.5 -76.5t77.5 -27.5q47 0 77 27.5t30 76.5q0 50 -30 78.5t-77 28.5 q-45 0 -74.5 -28.5t-29.5 -78.5z" /> +<glyph unicode="&#xe6;" horiz-adv-x="1726" d="M94 367q0 201 69 378t188.5 279t260.5 102q88 0 152 -43.5t108 -134.5h9l63 158h148l-25 -117q51 63 131 100t180 37q140 0 220.5 -76.5t80.5 -201.5q0 -182 -166.5 -284.5t-474.5 -102.5h-45l-4 -60q0 -117 60.5 -177t175.5 -60q125 0 305 84v-189q-175 -79 -344 -79 q-222 0 -305 137l-23 -117h-151l20 176h-8q-85 -106 -165.5 -151t-174.5 -45q-134 0 -209.5 103t-75.5 284zM332 373q0 -105 37 -154t96 -49q85 0 162.5 80.5t125.5 215.5t48 267q0 91 -38.5 146t-113.5 55q-85 0 -159.5 -80t-116 -211t-41.5 -270zM1022 633h31 q187 0 293 53.5t106 149.5q0 58 -34 84t-85 26q-103 0 -188.5 -86t-122.5 -227z" /> +<glyph unicode="&#xe7;" horiz-adv-x="954" d="M94 389q0 207 73.5 376.5t206.5 265t302 95.5q164 0 297 -61l-70 -184q-122 53 -221 53q-150 0 -250 -153.5t-100 -379.5q0 -111 56 -171t155 -60q74 0 138.5 22t129.5 54v-195q-140 -71 -305 -71q-196 0 -304 106t-108 303zM197 -342q47 -14 96 -14q137 0 137 96 q0 40 -35 61.5t-104 30.5l98 168h146l-50 -96q72 -25 104 -67t32 -101q0 -106 -82 -167t-224 -61q-64 0 -118 15v135z" /> +<glyph unicode="&#xe8;" horiz-adv-x="1075" d="M94 401q0 198 77.5 368.5t210 263.5t296.5 93q161 0 250.5 -72.5t89.5 -205.5q0 -182 -166.5 -284.5t-474.5 -102.5h-43l-2 -31v-29q0 -111 56.5 -174t168.5 -63q72 0 143 19t168 65v-187q-96 -44 -176.5 -62.5t-179.5 -18.5q-197 0 -307.5 111t-110.5 310zM362 633h29 q188 0 294 53.5t106 151.5q0 51 -32 79.5t-95 28.5q-96 0 -180.5 -86t-121.5 -227zM436 1548v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="&#xe9;" horiz-adv-x="1075" d="M94 401q0 198 77.5 368.5t210 263.5t296.5 93q161 0 250.5 -72.5t89.5 -205.5q0 -182 -166.5 -284.5t-474.5 -102.5h-43l-2 -31v-29q0 -111 56.5 -174t168.5 -63q72 0 143 19t168 65v-187q-96 -44 -176.5 -62.5t-179.5 -18.5q-197 0 -307.5 111t-110.5 310zM362 633h29 q188 0 294 53.5t106 151.5q0 51 -32 79.5t-95 28.5q-96 0 -180.5 -86t-121.5 -227zM557 1241v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="&#xea;" horiz-adv-x="1075" d="M94 401q0 198 77.5 368.5t210 263.5t296.5 93q161 0 250.5 -72.5t89.5 -205.5q0 -182 -166.5 -284.5t-474.5 -102.5h-43l-2 -31v-29q0 -111 56.5 -174t168.5 -63q72 0 143 19t168 65v-187q-96 -44 -176.5 -62.5t-179.5 -18.5q-197 0 -307.5 111t-110.5 310zM362 633h29 q188 0 294 53.5t106 151.5q0 51 -32 79.5t-95 28.5q-96 0 -180.5 -86t-121.5 -227zM320 1241v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="&#xeb;" horiz-adv-x="1075" d="M94 401q0 198 77.5 368.5t210 263.5t296.5 93q161 0 250.5 -72.5t89.5 -205.5q0 -182 -166.5 -284.5t-474.5 -102.5h-43l-2 -31v-29q0 -111 56.5 -174t168.5 -63q72 0 143 19t168 65v-187q-96 -44 -176.5 -62.5t-179.5 -18.5q-197 0 -307.5 111t-110.5 310zM362 633h29 q188 0 294 53.5t106 151.5q0 51 -32 79.5t-95 28.5q-96 0 -180.5 -86t-121.5 -227zM388 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM771 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102 t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="&#xec;" horiz-adv-x="563" d="M47 0l236 1106h235l-235 -1106h-236zM159 1548v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="&#xed;" horiz-adv-x="563" d="M47 0l236 1106h235l-235 -1106h-236zM308 1241v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="&#xee;" horiz-adv-x="563" d="M47 0l236 1106h235l-235 -1106h-236zM64 1241v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="&#xef;" horiz-adv-x="563" d="M47 0l236 1106h235l-235 -1106h-236zM142 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM525 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="&#xf0;" horiz-adv-x="1174" d="M80 389q0 162 65.5 299t184.5 215t266 78q96 0 168 -38.5t113 -108.5h6q-10 243 -133 383l-250 -142l-72 129l219 121q-44 41 -135 96l106 152q129 -72 209 -146l250 138l70 -127l-217 -121q155 -205 155 -512q0 -255 -73 -444.5t-204 -285t-312 -95.5q-197 0 -306.5 107 t-109.5 302zM317 377q0 -104 49 -159.5t142 -55.5q92 0 161.5 59.5t108.5 159t39 205.5q0 97 -52 155t-144 58q-91 0 -160.5 -56t-106.5 -153.5t-37 -212.5z" /> +<glyph unicode="&#xf1;" horiz-adv-x="1208" d="M47 0l236 1106h184l-21 -205h9q83 118 171 171.5t191 53.5q134 0 207.5 -76t73.5 -216q0 -69 -23 -181l-137 -653h-236l142 672q18 90 18 131q0 131 -129 131q-72 0 -142 -57t-126 -164.5t-84 -243.5l-98 -469h-236zM363 1239q57 285 256 285q46 0 85 -17.5t72.5 -38 t63.5 -38t59 -17.5q40 0 65 26.5t48 86.5h137q-66 -285 -260 -285q-45 0 -82.5 17t-71.5 37.5t-65.5 37.5t-63.5 17q-38 0 -63 -27.5t-43 -83.5h-137z" /> +<glyph unicode="&#xf2;" horiz-adv-x="1174" d="M94 408q0 199 71.5 365t200.5 258.5t298 92.5q195 0 305 -116t110 -316q0 -202 -73 -367.5t-200.5 -254t-293.5 -88.5q-192 0 -305 114.5t-113 311.5zM332 403q0 -111 49.5 -170t146.5 -59q90 0 162 68t112 190.5t40 269.5q0 107 -49 167.5t-140 60.5q-93 0 -166.5 -71.5 t-114 -194t-40.5 -261.5zM444 1548v21h245q47 -154 132 -303v-25h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="&#xf3;" horiz-adv-x="1174" d="M94 408q0 199 71.5 365t200.5 258.5t298 92.5q195 0 305 -116t110 -316q0 -202 -73 -367.5t-200.5 -254t-293.5 -88.5q-192 0 -305 114.5t-113 311.5zM332 403q0 -111 49.5 -170t146.5 -59q90 0 162 68t112 190.5t40 269.5q0 107 -49 167.5t-140 60.5q-93 0 -166.5 -71.5 t-114 -194t-40.5 -261.5zM580 1241v25q97 108 225 303h264v-19q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="&#xf4;" horiz-adv-x="1174" d="M94 408q0 199 71.5 365t200.5 258.5t298 92.5q195 0 305 -116t110 -316q0 -202 -73 -367.5t-200.5 -254t-293.5 -88.5q-192 0 -305 114.5t-113 311.5zM332 403q0 -111 49.5 -170t146.5 -59q90 0 162 68t112 190.5t40 269.5q0 107 -49 167.5t-140 60.5q-93 0 -166.5 -71.5 t-114 -194t-40.5 -261.5zM341 1241v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="&#xf5;" horiz-adv-x="1174" d="M94 408q0 199 71.5 365t200.5 258.5t298 92.5q195 0 305 -116t110 -316q0 -202 -73 -367.5t-200.5 -254t-293.5 -88.5q-192 0 -305 114.5t-113 311.5zM332 403q0 -111 49.5 -170t146.5 -59q90 0 162 68t112 190.5t40 269.5q0 107 -49 167.5t-140 60.5q-93 0 -166.5 -71.5 t-114 -194t-40.5 -261.5zM328 1239q57 285 256 285q46 0 85 -17.5t72.5 -38t63.5 -38t59 -17.5q40 0 65 26.5t48 86.5h137q-66 -285 -260 -285q-45 0 -82.5 17t-71.5 37.5t-65.5 37.5t-63.5 17q-38 0 -63 -27.5t-43 -83.5h-137z" /> +<glyph unicode="&#xf6;" horiz-adv-x="1174" d="M94 408q0 199 71.5 365t200.5 258.5t298 92.5q195 0 305 -116t110 -316q0 -202 -73 -367.5t-200.5 -254t-293.5 -88.5q-192 0 -305 114.5t-113 311.5zM332 403q0 -111 49.5 -170t146.5 -59q90 0 162 68t112 190.5t40 269.5q0 107 -49 167.5t-140 60.5q-93 0 -166.5 -71.5 t-114 -194t-40.5 -261.5zM409 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM792 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="&#xf7;" d="M117 631v180h936v-180h-936zM459 373q0 64 31.5 99.5t93.5 35.5t94.5 -36t32.5 -99q0 -64 -34.5 -100.5t-92.5 -36.5t-91.5 35.5t-33.5 101.5zM459 1071q0 64 31.5 99.5t93.5 35.5t94.5 -36t32.5 -99q0 -64 -34.5 -100.5t-92.5 -36.5t-91.5 35.5t-33.5 101.5z" /> +<glyph unicode="&#xf8;" horiz-adv-x="1174" d="M51 6l115 141q-70 104 -70 261q0 200 70.5 365t199.5 258t298 93q136 0 239 -61l86 108l125 -96l-100 -117q63 -100 63 -258q0 -208 -74 -376t-200.5 -255t-288.5 -87q-137 0 -235 59l-105 -131zM324 426q0 -39 8 -74l442 549q-45 35 -121 35q-141 0 -235 -145.5 t-94 -364.5zM408 201q41 -33 120 -33q89 0 163 66.5t116.5 184t42.5 257.5q0 45 -6 67z" /> +<glyph unicode="&#xf9;" horiz-adv-x="1208" d="M111 274q0 63 12 124.5t24 123.5l123 584h236l-129 -610q-31 -141 -31 -193q0 -133 127 -133q72 0 143 57t126 162.5t85 247.5l99 469h233l-233 -1106h-185l21 205h-8q-82 -116 -171 -170.5t-192 -54.5q-134 0 -207 76t-73 218zM446 1548v21h245q47 -154 132 -303v-25 h-144q-65 63 -132 151.5t-101 155.5z" /> +<glyph unicode="&#xfa;" horiz-adv-x="1208" d="M111 274q0 63 12 124.5t24 123.5l123 584h236l-129 -610q-31 -141 -31 -193q0 -133 127 -133q72 0 143 57t126 162.5t85 247.5l99 469h233l-233 -1106h-185l21 205h-8q-82 -116 -171 -170.5t-192 -54.5q-134 0 -207 76t-73 218zM623 1241v25q97 108 225 303h264v-19 q-54 -66 -158 -161.5t-175 -147.5h-156z" /> +<glyph unicode="&#xfb;" horiz-adv-x="1208" d="M111 274q0 63 12 124.5t24 123.5l123 584h236l-129 -610q-31 -141 -31 -193q0 -133 127 -133q72 0 143 57t126 162.5t85 247.5l99 469h233l-233 -1106h-185l21 205h-8q-82 -116 -171 -170.5t-192 -54.5q-134 0 -207 76t-73 218zM370 1241v25q138 128 201 195.5t90 107.5 h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="&#xfc;" horiz-adv-x="1208" d="M111 274q0 63 12 124.5t24 123.5l123 584h236l-129 -610q-31 -141 -31 -193q0 -133 127 -133q72 0 143 57t126 162.5t85 247.5l99 469h233l-233 -1106h-185l21 205h-8q-82 -116 -171 -170.5t-192 -54.5q-134 0 -207 76t-73 218zM432 1380q0 60 35 98t98 38 q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM815 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="&#xfd;" horiz-adv-x="1004" d="M-170 -285q75 -16 125 -16q74 0 134 43.5t124 155.5l51 92l-164 1116h232l63 -531q9 -62 16 -174.5t7 -181.5h6q86 215 135 313l293 574h254l-688 -1280q-90 -165 -196 -241.5t-249 -76.5q-76 0 -143 19v188zM501 1241v25q97 108 225 303h264v-19q-54 -66 -158 -161.5 t-175 -147.5h-156z" /> +<glyph unicode="&#xfe;" horiz-adv-x="1200" d="M-55 -492l432 2048h235q-48 -223 -73 -339t-76 -291h8q155 200 328 200q144 0 224.5 -102t80.5 -287q0 -204 -68 -381.5t-184.5 -276.5t-265.5 -99q-94 0 -165 45.5t-114 130.5h-8q-7 -91 -25 -185l-96 -463h-233zM369 373q0 -98 46 -150.5t132 -52.5t159.5 77t116.5 209 t43 277q0 100 -41 150.5t-118 50.5q-84 0 -163 -81t-127 -213.5t-48 -266.5z" /> +<glyph unicode="&#xff;" horiz-adv-x="1004" d="M-170 -285q75 -16 125 -16q74 0 134 43.5t124 155.5l51 92l-164 1116h232l63 -531q9 -62 16 -174.5t7 -181.5h6q86 215 135 313l293 574h254l-688 -1280q-90 -165 -196 -241.5t-249 -76.5q-76 0 -143 19v188zM323 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5 q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM706 1380q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="&#x131;" horiz-adv-x="563" d="M47 0l236 1106h235l-235 -1106h-236z" /> +<glyph unicode="&#x152;" horiz-adv-x="1798" d="M135 543q0 267 98.5 487.5t269.5 337.5t388 117q145 0 223 -23h760l-43 -205h-539l-84 -395h504l-43 -200h-504l-96 -459h539l-43 -203h-717q-84 -20 -170 -20q-259 0 -401 149.5t-142 413.5zM383 545q0 -173 81.5 -267t227.5 -94q74 0 139 27l222 1038q-68 31 -181 31 q-138 0 -250 -96t-175.5 -266.5t-63.5 -372.5z" /> +<glyph unicode="&#x153;" horiz-adv-x="1788" d="M94 410q0 206 73.5 372.5t201 254t293.5 87.5q237 0 335 -192q73 91 174 142.5t226 51.5q159 0 246.5 -74.5t87.5 -203.5q0 -183 -165.5 -285t-471.5 -102h-47l-3 -60q0 -111 56.5 -174t169.5 -63q69 0 134.5 17.5t176.5 66.5v-189q-91 -43 -175 -61t-181 -18 q-120 0 -212.5 46t-140.5 138q-137 -182 -374 -182q-186 0 -295 115.5t-109 312.5zM332 412q0 -116 48.5 -177t139.5 -61q143 0 229.5 146.5t86.5 381.5q0 111 -49.5 169.5t-139.5 58.5q-87 0 -157.5 -64t-114 -186.5t-43.5 -267.5zM1073 633h31q189 0 294 54t105 155 q0 48 -30 76t-87 28q-105 0 -192 -85.5t-121 -227.5z" /> +<glyph unicode="&#x178;" horiz-adv-x="1092" d="M186 1462h242l154 -669l432 669h266l-623 -913l-114 -549h-238l119 553zM440 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102t-93.5 -37q-47 0 -78 23.5t-31 74.5zM823 1718q0 60 35 98t98 38q48 0 76.5 -23.5t28.5 -71.5q0 -65 -35.5 -102 t-93.5 -37q-47 0 -78 23.5t-31 74.5z" /> +<glyph unicode="&#x2c6;" horiz-adv-x="1135" d="M354 1241v25q138 128 201 195.5t90 107.5h248q38 -99 174 -303v-25h-152q-76 63 -161 178q-131 -110 -236 -178h-164z" /> +<glyph unicode="&#x2da;" horiz-adv-x="1182" d="M541 1464q0 103 65 164.5t168 61.5q104 0 171 -60.5t67 -163.5q0 -104 -66 -165.5t-172 -61.5t-169.5 61t-63.5 164zM670 1464q0 -49 26.5 -76.5t77.5 -27.5q47 0 77 27.5t30 76.5q0 50 -30 78.5t-77 28.5q-45 0 -74.5 -28.5t-29.5 -78.5z" /> +<glyph unicode="&#x2dc;" horiz-adv-x="1135" d="M326 1239q57 285 256 285q46 0 85 -17.5t72.5 -38t63.5 -38t59 -17.5q40 0 65 26.5t48 86.5h137q-66 -285 -260 -285q-45 0 -82.5 17t-71.5 37.5t-65.5 37.5t-63.5 17q-38 0 -63 -27.5t-43 -83.5h-137z" /> +<glyph unicode="&#x2000;" horiz-adv-x="953" /> +<glyph unicode="&#x2001;" horiz-adv-x="1907" /> +<glyph unicode="&#x2002;" horiz-adv-x="953" /> +<glyph unicode="&#x2003;" horiz-adv-x="1907" /> +<glyph unicode="&#x2004;" horiz-adv-x="635" /> +<glyph unicode="&#x2005;" horiz-adv-x="476" /> +<glyph unicode="&#x2006;" horiz-adv-x="317" /> +<glyph unicode="&#x2007;" horiz-adv-x="317" /> +<glyph unicode="&#x2008;" horiz-adv-x="238" /> +<glyph unicode="&#x2009;" horiz-adv-x="381" /> +<glyph unicode="&#x200a;" horiz-adv-x="105" /> +<glyph unicode="&#x2010;" horiz-adv-x="649" d="M47 446l45 203h502l-45 -203h-502z" /> +<glyph unicode="&#x2011;" horiz-adv-x="649" d="M47 446l45 203h502l-45 -203h-502z" /> +<glyph unicode="&#x2012;" horiz-adv-x="649" d="M47 446l45 203h502l-45 -203h-502z" /> +<glyph unicode="&#x2013;" horiz-adv-x="983" d="M47 453l43 194h838l-43 -194h-838z" /> +<glyph unicode="&#x2014;" horiz-adv-x="1966" d="M47 453l43 194h1821l-43 -194h-1821z" /> +<glyph unicode="&#x2018;" horiz-adv-x="393" d="M119 983q34 76 106.5 209t159.5 270h176q-122 -286 -199 -501h-237z" /> +<glyph unicode="&#x2019;" horiz-adv-x="393" d="M115 961q43 95 106 255t92 246h238l8 -22q-37 -83 -110.5 -217.5t-155.5 -261.5h-178z" /> +<glyph unicode="&#x201a;" horiz-adv-x="530" d="M-102 -264q105 238 200 502h236l8 -23q-108 -233 -266 -479h-178z" /> +<glyph unicode="&#x201c;" horiz-adv-x="803" d="M119 983q34 76 106.5 209t159.5 270h176q-122 -286 -199 -501h-237zM526 983q84 190 267 479h176q-122 -286 -199 -501h-235z" /> +<glyph unicode="&#x201d;" horiz-adv-x="803" d="M115 961q43 95 106 255t92 246h238l8 -22q-37 -83 -110.5 -217.5t-155.5 -261.5h-178zM522 961q51 114 109 261t90 240h237l9 -22q-98 -220 -269 -479h-176z" /> +<glyph unicode="&#x201e;" horiz-adv-x="938" d="M-102 -264q105 238 200 502h236l8 -23q-108 -233 -266 -479h-178zM307 -264q120 281 199 502h235l9 -23q-92 -206 -267 -479h-176z" /> +<glyph unicode="&#x2022;" horiz-adv-x="756" d="M152 684q0 156 83.5 252t223.5 96q100 0 158.5 -54.5t58.5 -168.5q0 -156 -82 -252t-227 -96q-102 0 -158.5 57.5t-56.5 165.5z" /> +<glyph unicode="&#x2026;" horiz-adv-x="1634" d="M834 94q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -78 -47.5 -129.5t-124.5 -51.5q-66 0 -97.5 35.5t-31.5 87.5zM594 94q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -78 -47.5 -129.5t-124.5 -51.5q-66 0 -97.5 35.5t-31.5 87.5zM293 94 q0 83 47 132.5t131 49.5q56 0 89.5 -31.5t33.5 -92.5q0 -78 -47.5 -129.5t-124.5 -51.5q-66 0 -97.5 35.5t-31.5 87.5z" /> +<glyph unicode="&#x202f;" horiz-adv-x="381" /> +<glyph unicode="&#x2039;" horiz-adv-x="621" d="M80 549v24l395 422l135 -118l-288 -334l153 -367l-178 -76z" /> +<glyph unicode="&#x203a;" horiz-adv-x="621" d="M10 211l289 334l-154 366l179 76l217 -448v-25l-396 -422z" /> +<glyph unicode="&#x2044;" horiz-adv-x="262" d="M-510 0l1085 1462h195l-1083 -1462h-197z" /> +<glyph unicode="&#x205f;" horiz-adv-x="476" /> +<glyph unicode="&#x2074;" horiz-adv-x="745" d="M70 762l26 137l477 569h197l-121 -563h123l-29 -143h-122l-39 -176h-183l39 176h-368zM268 905h199l52 221l34 129q-32 -51 -98 -131z" /> +<glyph unicode="&#x20ac;" d="M51 492l33 155h139q15 95 27 139h-137l32 154h148q92 260 255.5 401.5t371.5 141.5q88 0 164.5 -22t156.5 -77l-102 -180q-54 34 -107 56t-119 22q-118 0 -214.5 -87t-161.5 -255h387l-33 -154h-402q-18 -67 -28 -139h340l-33 -155h-319q0 -161 60.5 -234.5t195.5 -73.5 q120 0 258 60v-203q-129 -61 -306 -61q-216 0 -330 130t-114 382h-162z" /> +<glyph unicode="&#x2122;" horiz-adv-x="1534" d="M113 1335v127h540v-127h-198v-594h-146v594h-196zM709 741v721h215l170 -534l182 534h205v-721h-146v418l4 121h-6l-184 -539h-119l-178 539h-6l4 -115v-424h-141z" /> +<glyph unicode="&#xe000;" horiz-adv-x="1105" d="M0 1105h1105v-1105h-1105v1105z" /> +<glyph unicode="&#xfb01;" horiz-adv-x="1257" d="M-225 -279q64 -20 114 -20q134 0 177 205l217 1022h-179l21 106l194 76l21 92q44 198 134.5 281.5t256.5 83.5q115 0 211 -43l-61 -176q-74 28 -136 28q-69 0 -110.5 -43t-63.5 -141l-18 -86h229l-37 -178h-229l-223 -1053q-40 -189 -131 -278t-238 -89q-90 0 -149 23 v190zM739 0l236 1106h235l-235 -1106h-236zM1022 1378q0 68 39 110t110 42q53 0 86 -26.5t33 -80.5q0 -71 -40 -112t-105 -41q-53 0 -88 26t-35 82z" /> +<glyph unicode="&#xfb02;" horiz-adv-x="1257" d="M-225 -279q64 -20 114 -20q134 0 177 205l217 1022h-179l21 106l194 76l21 92q44 198 134.5 281.5t256.5 83.5q115 0 211 -43l-61 -176q-74 28 -136 28q-69 0 -110.5 -43t-63.5 -141l-18 -86h229l-37 -178h-229l-223 -1053q-40 -189 -131 -278t-238 -89q-90 0 -149 23 v190zM739 0l330 1556h235l-331 -1556h-234z" /> +<glyph unicode="&#xfb03;" horiz-adv-x="1931" d="M-225 -279q64 -20 114 -20q133 0 177 205l217 1022h-179l21 106l194 76l21 92q44 198 134.5 281.5t256.5 83.5q115 0 211 -43l-61 -176q-74 28 -136 28q-69 0 -110.5 -43t-63.5 -141l-18 -86h438l23 96q44 197 133 281t256 84q117 0 213 -43l-62 -176q-74 28 -135 28 q-71 0 -111.5 -43t-62.5 -141l-18 -86h229l-39 -178h-227l-223 -1053q-43 -192 -133.5 -279.5t-235.5 -87.5q-95 0 -149 23v190q60 -20 114 -20q136 0 176 205l215 1022h-438l-223 -1053q-40 -189 -131 -278t-238 -89q-90 0 -149 23v190zM1415 0l236 1106h233l-235 -1106 h-234zM1698 1378q0 68 39 110t108 42q54 0 86.5 -26.5t32.5 -80.5q0 -71 -39.5 -112t-105.5 -41q-51 0 -86 26t-35 82z" /> +<glyph unicode="&#xfb04;" horiz-adv-x="1931" d="M-225 -279q64 -20 114 -20q133 0 177 205l217 1022h-179l21 106l194 76l21 92q44 198 134.5 281.5t256.5 83.5q115 0 211 -43l-61 -176q-74 28 -136 28q-69 0 -110.5 -43t-63.5 -141l-18 -86h438l23 96q44 197 133 281t256 84q117 0 213 -43l-62 -176q-74 28 -135 28 q-71 0 -111.5 -43t-62.5 -141l-18 -86h229l-39 -178h-227l-223 -1053q-43 -192 -133.5 -279.5t-235.5 -87.5q-95 0 -149 23v190q60 -20 114 -20q136 0 176 205l215 1022h-438l-223 -1053q-40 -189 -131 -278t-238 -89q-90 0 -149 23v190zM1413 0l332 1556h233l-329 -1556 h-236z" /> +</font> +</defs></svg> +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/fonts/OpenSans-SemiboldItalic-webfont.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/stylesheet.css b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/open-sans/stylesheet.css @@ -0,0 +1,136 @@ +/***** Font Definition for Open Sans. This stylesheet comes from qrohlf.com/posts/better-opensans *****/ + +/* Regular */ +@font-face { + font-family: 'Open Sans'; + + src: url('fonts/OpenSans-Regular-webfont.eot'); + src: url('fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), + url('fonts/OpenSans-Regular-webfont.woff') format('woff'), + url('fonts/OpenSans-Regular-webfont.ttf') format('truetype'), + url('fonts/OpenSans-Regular-webfont.svg#OpenSansRegular') format('svg'); + font-weight: normal; + font-weight: 400; + font-style: normal; + +} + +/* Italic */ +@font-face { + font-family: 'Open Sans'; + src: url('fonts/OpenSans-Italic-webfont.eot'); + src: url('fonts/OpenSans-Italic-webfont.eot?#iefix') format('embedded-opentype'), + url('fonts/OpenSans-Italic-webfont.woff') format('woff'), + url('fonts/OpenSans-Italic-webfont.ttf') format('truetype'), + url('fonts/OpenSans-Italic-webfont.svg#OpenSansItalic') format('svg'); + font-weight: normal; + font-weight: 400; + font-style: italic; + +} + +/* Light */ +@font-face { + font-family: 'Open Sans'; + src: url('fonts/OpenSans-Light-webfont.eot'); + src: url('fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'), + url('fonts/OpenSans-Light-webfont.woff') format('woff'), + url('fonts/OpenSans-Light-webfont.ttf') format('truetype'), + url('fonts/OpenSans-Light-webfont.svg#OpenSansLight') format('svg'); + font-weight: 200; + font-style: normal; + +} + +/* Light Italic */ +@font-face { + font-family: 'Open Sans'; + src: url('fonts/OpenSans-LightItalic-webfont.eot'); + src: url('fonts/OpenSans-LightItalic-webfont.eot?#iefix') format('embedded-opentype'), + url('fonts/OpenSans-LightItalic-webfont.woff') format('woff'), + url('fonts/OpenSans-LightItalic-webfont.ttf') format('truetype'), + url('fonts/OpenSans-LightItalic-webfont.svg#OpenSansLightItalic') format('svg'); + font-weight: 200; + font-style: italic; + +} + +/* Semibold */ +@font-face { + font-family: 'Open Sans'; + src: url('fonts/OpenSans-Semibold-webfont.eot'); + src: url('fonts/OpenSans-Semibold-webfont.eot?#iefix') format('embedded-opentype'), + url('fonts/OpenSans-Semibold-webfont.woff') format('woff'), + url('fonts/OpenSans-Semibold-webfont.ttf') format('truetype'), + url('fonts/OpenSans-Semibold-webfont.svg#OpenSansSemibold') format('svg'); + font-weight: 500; + font-style: normal; + +} + +/* Semibold Italic */ +@font-face { + font-family: 'Open Sans'; + src: url('fonts/OpenSans-SemiboldItalic-webfont.eot'); + src: url('fonts/OpenSans-SemiboldItalic-webfont.eot?#iefix') format('embedded-opentype'), + url('fonts/OpenSans-SemiboldItalic-webfont.woff') format('woff'), + url('fonts/OpenSans-SemiboldItalic-webfont.ttf') format('truetype'), + url('fonts/OpenSans-SemiboldItalic-webfont.svg#OpenSansSemiboldItalic') format('svg'); + font-weight: 500; + font-style: italic; + +} + +/* Bold */ +@font-face { + font-family: 'Open Sans'; + src: url('fonts/OpenSans-Bold-webfont.eot'); + src: url('fonts/OpenSans-Bold-webfont.eot?#iefix') format('embedded-opentype'), + url('fonts/OpenSans-Bold-webfont.woff') format('woff'), + url('fonts/OpenSans-Bold-webfont.ttf') format('truetype'), + url('fonts/OpenSans-Bold-webfont.svg#OpenSansBold') format('svg'); + font-weight: bold; + font-weight: 700; + font-style: normal; + +} + +/* Bold Italic */ +@font-face { + font-family: 'Open Sans'; + src: url('fonts/OpenSans-BoldItalic-webfont.eot'); + src: url('fonts/OpenSans-BoldItalic-webfont.eot?#iefix') format('embedded-opentype'), + url('fonts/OpenSans-BoldItalic-webfont.woff') format('woff'), + url('fonts/OpenSans-BoldItalic-webfont.ttf') format('truetype'), + url('fonts/OpenSans-BoldItalic-webfont.svg#OpenSansBoldItalic') format('svg'); + font-weight: bold; + font-weight: 700; + font-style: italic; + +} + +/* Extra Bold */ +@font-face { + font-family: 'Open Sans'; + src: url('fonts/OpenSans-ExtraBold-webfont.eot'); + src: url('fonts/OpenSans-ExtraBold-webfont.eot?#iefix') format('embedded-opentype'), + url('fonts/OpenSans-ExtraBold-webfont.woff') format('woff'), + url('fonts/OpenSans-ExtraBold-webfont.ttf') format('truetype'), + url('fonts/OpenSans-ExtraBold-webfont.svg#OpenSansExtrabold') format('svg'); + font-weight: 900; + font-style: normal; + +} + +/* Extra Bold Italic */ +@font-face { + font-family: 'Open Sans'; + src: url('fonts/OpenSans-ExtraBoldItalic-webfont.eot'); + src: url('fonts/OpenSans-ExtraBoldItalic-webfont.eot?#iefix') format('embedded-opentype'), + url('fonts/OpenSans-ExtraBoldItalic-webfont.woff') format('woff'), + url('fonts/OpenSans-ExtraBoldItalic-webfont.ttf') format('truetype'), + url('fonts/OpenSans-ExtraBoldItalic-webfont.svg#OpenSansExtraboldItalic') format('svg'); + font-weight: 900; + font-style: italic; + +} diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Black.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Black.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Bold.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Bold.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-ExtraLight.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-ExtraLight.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Light.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Light.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Regular.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Regular.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Semibold.eot b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/EOT/SourceSerifPro-Semibold.eot Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/LICENSE.txt b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2014 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Black.otf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Black.otf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Bold.otf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Bold.otf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-ExtraLight.otf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-ExtraLight.otf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Light.otf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Light.otf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Regular.otf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Regular.otf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Semibold.otf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/OTF/SourceSerifPro-Semibold.otf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/README.md b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/README.md @@ -0,0 +1,18 @@ +# Source Serif Pro + +Source Serif Pro is a set of OpenType fonts to complement the [Source Sans Pro](https://github.com/adobe-fonts/source-sans-pro) family. +In addition to a functional OpenType font, this open source project provides all of the source files that were used to build this OpenType font by using the AFDKO makeotf tool. + +## Installation instructions + +* [Mac OS X](http://support.apple.com/kb/HT2509) +* [Windows](http://windows.microsoft.com/en-us/windows-vista/install-or-uninstall-fonts) +* [Linux/Unix-based systems](https://github.com/adobe-fonts/source-code-pro/issues/17#issuecomment-8967116) + +## Getting Involved + +Send suggestions for changes to the Source Serif OpenType font project maintainer, [Frank Grießhammer](mailto:opensourcefonts@adobe.com?subject=[GitHub] Source Serif Pro), for consideration. + +## Further information + +For information about the design and background of Source Serif, please refer to the [official font readme file](http://htmlpreview.github.io/?https://github.com/adobe-fonts/source-serif-pro/blob/master/SourceSerifProReadMe.html). diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/ReadMe.html b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/ReadMe.html @@ -0,0 +1,72 @@ +<!DOCTYPE html> +<html> +<head> + <title>Read Me File for Adobe® OpenType® Fonts</title> + <meta charset="utf-8" /> +</head> +<body bgcolor="white" link="#ce0000" alink="#ce0000" vlink="#9c6363"> + <h2><font color="#333333" +face="verdana,geneva,arial">Adobe&reg; OpenType&reg; Fonts</font></h2> + <p><font size="2" face="verdana,geneva,arial">Thank +you for licensing Adobe OpenType fonts. In order to ensure that you +have the most up-to-date product information, Adobe has posted <a +href="http://www.adobe.com/type/browser/OTReadMe.html">an OpenType +Read Me file</a> on the Adobe web site that contains information such +as minimum system requirements, technical support contact information +and software installation notes. We have also posted <a +href="http://www.adobe.com/type/browser/pdfs/OTGuide.pdf">an OpenType +User's Guide</a> in PDF format on the Adobe web site that can be +viewed online and downloaded to your computer. <P>If you have +licensed an Adobe OpenType Pro font, there may be additional PDF +documents, such as a specimen book, a glyph complement showing, and a +typeface-specific Read Me file, available on the typeface&#146;s +product pages on the Adobe web site. These additional files may be +viewed online or downloaded to your computer.<P>To get you started +quickly, below are links to localized installation instructions for +your fonts. + +<h4>Installation Instructions</h4><hr> +<p lang=en><b>English</b><br> +Instructions for installing this font can be found online at <a +href="http://www.adobe.com/type/browser/fontinstall/instructions_main.html">http://www.adobe.com/type/browser/fontinstall/instructions_main.html</a>.</p> +<p lang=fr><b>French / Fran&#231;ais</b><br> +Le mode d'installation de cette police de caract&#232;re se trouve en +ligne &#224; <a +href="http://www.adobe.com/type/browser/fontinstall/instructions_main.html">http://www.adobe.com/type/browser/fontinstall/instructions_main.html</a>.</p> +<p lang=de><b>German / Deutsch</b><br> +Die Anweisungen zur Installation dieser Schriftart finden Sie online +unter <a +href="http://www.adobe.com/type/browser/fontinstall/instructions_main.html">http://www.adobe.com/type/browser/fontinstall/instructions_main.html</a>.</p> +<p lang=it><b>Italian / Italiano</b><br> +Le istruzioni per l'installazione di questo font sono disponibili +online all'indirizzo <a +href="http://www.adobe.com/type/browser/fontinstall/instructions_main.html">http://www.adobe.com/type/browser/fontinstall/instructions_main.html</a>.</p> +<p lang=es><b>Spanish / Espa&#241;ol</b><br> +Las instrucciones para instalar esta fuente se pueden encontrar +online en <a +href="http://www.adobe.com/type/browser/fontinstall/instructions_main.html">http://www.adobe.com/type/browser/fontinstall/instructions_main.html</a>.</p> +<p lang=nl><b>Dutch / Hollands</b><br> +De instructies voor de installatie van dit lettertype vindt u op <a +href="http://www.adobe.com/type/browser/fontinstall/instructions_main.html">http://www.adobe.com/type/browser/fontinstall/instructions_main.html</a>.</p> +<p><b>Swedish / Svenska</b><br> +Anvisningar f&#246;r hur det h&#228;r teckensnittet installeras finns +online p&#229; <a +href="http://www.adobe.com/type/browser/fontinstall/instructions_main.html">http://www.adobe.com/type/browser/fontinstall/instructions_main.html</a>.</p> +<p><b>Norwegian / Norsk</b><br> +Instruksjoner for installering av skrifttypen finnes online p&#229; +<a +href="http://www.adobe.com/type/browser/fontinstall/instructions_main.html">http://www.adobe.com/type/browser/fontinstall/instructions_main.html</a>.</p> +<p><b>Finnish / Suomi</b><br> +Ohjeet t&#228;m&#228;n fontin asentamiseen l&#246;ytyv&#228;t +osoitteesta <a +href="http://www.adobe.com/type/browser/fontinstall/instructions_main.html">http://www.adobe.com/type/browser/fontinstall/instructions_main.html</a>.</p> +<p><b>Danish / Dansk</b><br> +Du finder en vejledning i installation af denne skrifttype online +p&#229; adressen <a +href="http://www.adobe.com/type/browser/fontinstall/instructions_main.html">http://www.adobe.com/type/browser/fontinstall/instructions_main.html</a>.</p> +<p lang=ja><b>Japanese / 日本語</b><br> +このフォントをインストールする手順は、オンラインで <a +href="http://www.adobe.com/type/browser/fontinstall/instructions_main.html">http://www.adobe.com/type/browser/fontinstall/instructions_main.html</a> +を参照してください。</p> +</body> +</html> diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/SourceSerifProReadMe.html b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/SourceSerifProReadMe.html @@ -0,0 +1,189 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<!-- Read-me Template Version 1.003 Jan 145 2013 --> +<html> + <head> + <meta http-equiv="content-type" content="text/html" /> + <meta name="title" content="Read Me File for Source Serif Pro" /> + <meta name="description" content="Read Me file for Source Serif Pro ..." /> + <title>Source Serif Pro Read Me</title> + <style type="text/css" media="screen"> + /*********************** fonts ************************/ + body {font-family: sans-serif; font-weight: normal; font-size: 10pt; color: #000000; margin: 0px; background-color: white;} + h1 {display:inline; font-family: sans-serif; font-weight: normal; color: #999999;} + h2 {display:inline; font-size: 10pt; font-family: sans-serif; font-weight: bold; color: #666666;} + hFooter {font-family: sans-serif; font-weight: normal; font-size: 7pt; color: #000000; margin: 0px; background-color: white;} + /*********************** links ************************/ + a:link {color:#004477; text-decoration:none; margin: 0px 0px 0px 0px;} + a:visited {color:#6d7f8e; text-decoration:none; margin: 0px 0px 0px 0px;} + a:hover {color:#ff0000; text-decoration:none; margin: 0px 0px 0px 0px;} + /*********************** div tags ************************/ + #page {float:left; width:700px; margin:20px 20px 20px 20px;} + #subTitle {background-color:#e3e3e3; float:left; width:700px; border-bottom:solid #999999 1.0pt; border-bottom-alt:solid #999999 .5pt; padding:2px 0px 4px 0px;} + #title {background-color:#e3e3e3; float:left; width:700px; border-bottom:solid #999999 1.0pt; border-bottom-alt:solid #999999 .5pt; padding:2px 0px 4px 0px;} + #description {float:left; width:700px; padding:15px 0px 15px 0px;} .style6 {color: #666666} .style7 {color: #FF0000}</style> + </head> + <body> + <div id="page"> + <h1> + <span style="font-size:16pt">Source&#153; Serif Pro Read Me</span> + </h1> + <br /> + <div id="description"> + <p>This document contains late-breaking product information, updates, and troubleshooting tips. + <br /> + <br /> + <a href="#A1">Minimum system requirements and font installation instructions</a> + <br /> + <a href="#A2A">Font versions</a> + <br /> + <a href="#A2">Family information</a> + <br /> + <a href="#A3">Release Notes</a> + <br /> + <a href="#A8">Known issues</a> + <br /> + <a href="#A9">Customer care</a> + <br /> + <a href="#A10">Other resources</a> + <br /> + <a href="#A12"></a> + <br /></p> + </div> + <div id="title"> + <a name="A1" id="A1"></a> + <h2>Minimum system requirements and font installation instructions</h2> + </div> + <div id="description"> + <p>For information on minimum system requirements and font installation, see <span class="style7"> + <a title="http://www.adobe.com/go/learn_fontinstall_en" href="http://www.adobe.com/go/learn_fontinstall_en">http://www.adobe.com/go/learn_fontinstall_en</a>.</span></p> + </div> + <div id="title"> + <a name="A2A" id=A2A></a> + <h2>Font versions</h2> + </div> + <div id="description"> + <p>To check that you have the correct font file, compare the font version of your font file to the font version provided in the Release Notes section below.</p> + </div> + <div id="title"> + <h2> + <a name="A2" id="A2">Family information</a> + </h2> + </div> + <div id="description"> + <p> + <strong>History</strong> + </p>Source Serif Pro is a serif typeface in the transitional style, designed to complement Source Sans. Their close companionship is achieved by a careful match of letter proportions and typographic color. While designed to harmonize with its serif-less counterpart, Source Serif often takes its own direction, in part because the two are inspired by different historical precedents. Source Serif is loosely based on the work of Pierre Simon Fournier, and many idiosyncrasies typical to Fournier&rsquo;s designs (like the bottom serif on the b or the middle serif on the w) are also found in Source Serif. Without being a pure historical revival, Source Serif takes cues from the Fournier model and reworks it for a modern age.<br><br>Source Sans and Source Serif also have different personalities because they spring from the hands of different designers. Source Serif was designed by Frank Grie&#223;hammer, Source Sans was designed by Paul Hunt. Robert Slimbach consulted on both designs, which helped maintain the overall family harmony. Either design feels confident on its own but also works in combination with the other &mdash; just like their designers do.<br><br>Source Serif continues Adobe&rsquo;s line of high-quality open source typefaces. Designed for a digital environment, the letter shapes are simplified and highly readable. Its historical roots, combined with the guidance through an experienced designer give the typeface a strong character of its own that will shine when used for extended text on paper or on screen.<br><br>There is still more to come for Source Serif. Additional weights, Italic cuts, and Cyrillic and Greek language support are all planned. If you are interested in contributing to this open source project, please visit this project page for information on how to become involved. Source Serif Pro can be adapted and redistributed according to the terms of the Open Font License (OFL) agreement. + <p> + <strong>Menu Names And Style Linking</strong> + </p> +<p>In many Windows<sup>&reg;</sup> applications, instead of every font appearing on +the menu, fonts are grouped into style-linked sets, and only the name of +the base style font for a set is shown in the menu. The italic and the +bold weight fonts of the set (if any) are not shown in the font menu, but can still be +accessed by selecting the base style font, and then using the italic +and bold style buttons. In this family, such programs will show only the +following base style font names in the menu:</p> +<p>Source Serif Pro<br> +Source Serif Pro Black<br> +Source Serif Pro ExtraLight<br> +Source Serif Pro Light<br> +Source Serif Pro SemiBold<br></p> +<p>The other fonts in this family must be selected by choosing a menu name +and then a style option following the guide below.</p> +<table border="0"> +<tr> <td>Menu Name</td> <td> </td> <td>plus Style Option... </td> <td> </td> <td>selects this font</td> </tr> +<tr> <td>Source Serif Pro</td> <td> </td> <td>[none]</td> <td> </td> <td>Source Serif Pro Regular</td> </tr> +<tr> <td>Source Serif Pro</td> <td> </td> <td>Bold</td> <td> </td> <td>Source Serif Pro Bold</td> </tr> +<tr> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> +<tr> <td>Source Serif Pro Black</td> <td> </td> <td>[none]</td> <td> </td> <td>Source Serif Pro Black</td> </tr> +<tr> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> +<tr> <td>Source Serif Pro ExtraLight</td> <td> </td> <td>[none]</td> <td> </td> <td>Source Serif Pro ExtraLight</td> </tr> +<tr> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> +<tr> <td>Source Serif Pro Light</td> <td> </td> <td>[none]</td> <td> </td> <td>Source Serif Pro Light</td> </tr> +<tr> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> +<tr> <td>Source Serif Pro SemiBold</td> <td> </td> <td>[none]</td> <td> </td> <td>Source Serif Pro Semibold</td> </tr> +<tr> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> +</table> +<p>On the Mac OS operating system, although each font appears as a separate entry on the +font menu, users may also select fonts by means of style links. +Selecting a base style font and then using the style links (as described +above for Windows applications) enhances cross-platform document compatibility with +many applications, such as Microsoft Word and Adobe<sup>&reg;</sup> PageMaker<sup>&reg;</sup> software, +although it is unnecessary with more sophisticated Adobe applications +such as recent versions of Illustrator<sup>&reg;</sup>, Photoshop<sup>&reg;</sup> or +InDesign<sup>&reg;</sup> software.</p> +<p>One should not, however, select a base font which has no style-linked +variant, and then use the bold or italic styling button. Doing so will +either have no effect, or result in programmatic bolding or slanting of +the base font, which will usually produce inferior screen and print +results.</p> +</div> + <div id="title"> + <h2> + <a name="A3" id="A3">Release Notes</a> + </h2> + </div> + <div id="description"><p>For all fonts of family Source Serif Pro: version 1.017 created on Tue Sep 16 17:12:36 2014.</p> +<p>version 1.017 created 2014/09/16</p> +<ul> +<li> Added three more weights: Black, Light, ExtraLight.</li> +<li> Added missing L/lcommaaccent (U+013B/C) to all fonts.</li> +</ul> +<p>version 1.014 created 2014/04/27</p> +<ul> +<li> First release.</li> +</ul> +</div> + <div id="title"> + <h2> + <a name="A8" id="A8">Known issues</a> + </h2> + </div> + <div id="description"><ul> <li>Some glyphs in the font cannot be accessed unless you are using an OpenType<sup>&reg;</sup> compatible application. + </li> +</ul></div> + <div id="title"> + <h2> + <a name="A9" id="A9">Customer care</a> + </h2> + </div> + <div id="description"> + <p> + <strong>Customer Service</strong> + <br />Adobe Customer Service provides assistance with product information, sales, registration, and other non-technical issues. + To find out how to contact Adobe Customer Service, please visit <a href="http://www.adobe.com">Adobe.com</a> for your region or country and click on Contact Adobe.</p> + <p> + <strong>Support Plan Options and Technical Resources</strong> + <br />If you require technical assistance for your product, including information on free and paid support options and troubleshooting resources, more information is available at + <a title="http://www.adobe.com/go/support/" href="http://www.adobe.com/go/support/"> + <span title="http://www.adobe.com/go/support/">http://www.adobe.com/go/support/.</span> + </a> Outside of North America, go to + <a title="http://www.adobe.com/go/intlsupport/" href="http://www.adobe.com/go/intlsupport/"> + <span title="http://www.adobe.com/go/intlsupport/">http://www.adobe.com/go/intlsupport/.</span> + </a>Font specific resources include the <a href="http://helpx.adobe.com/font-folio-type.html">Font Folio and Type Product Help page</a> and the <a href="http://forums.adobe.com/community/typography_fonts">Adobe Type user-to-user forums</a>.</p> + </div> + <div id="title"> + <h2> + <a name="A10" id="A10">Other resources</a> + </h2> + </div> + <div id="description"> + <p> + <a href="http://www.adobe.com/type">Adobe Type Showroom</a> + <br /> + <a href="http://www.adobe.com/type/family_readmes.html">Index page for all family Read Me files</a> + <br /> + </p> + <p align="left"> + <br /> + Adobe, the Adobe Logo, Source, Illustrator, InDesign, PageMaker and Photoshop are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries. Windows and OpenType are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. Mac, Mac OS and TrueType are trademarks of Apple Inc., registered in the U.S. and other countries. All other trademarks are the property of their respective owners. <br /> + <br /> + <hFooter> + &copy; 2014 Adobe Systems Incorporated. All rights reserved.<br /><br />created 2014 Sep 24 + <hFooter> + </p> + </div> + </div> + </body> +</html> diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Black.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Black.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Bold.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Bold.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-ExtraLight.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-ExtraLight.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Light.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Light.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Regular.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Regular.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Semibold.ttf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/TTF/SourceSerifPro-Semibold.ttf Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Black.otf.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Black.otf.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Bold.otf.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Bold.otf.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-ExtraLight.otf.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-ExtraLight.otf.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Light.otf.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Light.otf.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Regular.otf.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Regular.otf.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Semibold.otf.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/OTF/SourceSerifPro-Semibold.otf.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Black.ttf.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Black.ttf.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Bold.ttf.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Bold.ttf.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-ExtraLight.ttf.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-ExtraLight.ttf.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Light.ttf.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Light.ttf.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Regular.ttf.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Regular.ttf.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Semibold.ttf.woff b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/WOFF/TTF/SourceSerifPro-Semibold.ttf.woff Binary files differ. diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/bower.json b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/bower.json @@ -0,0 +1,15 @@ +{ + "name": "source-serif-pro", + "version": "1.014", + "main": "source-serif-pro.css", + "homepage": "https://github.com/adobe-fonts/source-serif-pro", + "repository": { + "type": "git", + "url": "https://github.com/adobe-fonts/source-serif-pro.git" + }, + "authors": [ + { "name": "Frank Grießhammer" } + ], + "description": "Source Serif Pro font family by Adobe", + "license": "SIL OFL 1.1" +} diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/source-serif-pro.css b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/fonts/source-serif-pro/source-serif-pro.css @@ -0,0 +1,65 @@ +@font-face{ + font-family: 'Source Serif Pro'; + font-weight: 200; + font-style: normal; + font-stretch: normal; + src: url('EOT/SourceSerifPro-ExtraLight.eot') format('embedded-opentype'), + url('WOFF/OTF/SourceSerifPro-ExtraLight.otf.woff') format('woff'), + url('OTF/SourceSerifPro-ExtraLight.otf') format('opentype'), + url('TTF/SourceSerifPro-ExtraLight.ttf') format('truetype'); +} + +@font-face{ + font-family: 'Source Serif Pro'; + font-weight: 300; + font-style: normal; + font-stretch: normal; + src: url('EOT/SourceSerifPro-Light.eot') format('embedded-opentype'), + url('WOFF/OTF/SourceSerifPro-Light.otf.woff') format('woff'), + url('OTF/SourceSerifPro-Light.otf') format('opentype'), + url('TTF/SourceSerifPro-Light.ttf') format('truetype'); +} + +@font-face{ + font-family: 'Source Serif Pro'; + font-weight: 400; + font-style: normal; + font-stretch: normal; + src: url('EOT/SourceSerifPro-Regular.eot') format('embedded-opentype'), + url('WOFF/OTF/SourceSerifPro-Regular.otf.woff') format('woff'), + url('OTF/SourceSerifPro-Regular.otf') format('opentype'), + url('TTF/SourceSerifPro-Regular.ttf') format('truetype'); +} + +@font-face{ + font-family: 'Source Serif Pro'; + font-weight: 600; + font-style: normal; + font-stretch: normal; + src: url('EOT/SourceSerifPro-Semibold.eot') format('embedded-opentype'), + url('WOFF/OTF/SourceSerifPro-Semibold.otf.woff') format('woff'), + url('OTF/SourceSerifPro-Semibold.otf') format('opentype'), + url('TTF/SourceSerifPro-Semibold.ttf') format('truetype'); +} + +@font-face{ + font-family: 'Source Serif Pro'; + font-weight: 700; + font-style: normal; + font-stretch: normal; + src: url('EOT/SourceSerifPro-Bold.eot') format('embedded-opentype'), + url('WOFF/OTF/SourceSerifPro-Bold.otf.woff') format('woff'), + url('OTF/SourceSerifPro-Bold.otf') format('opentype'), + url('TTF/SourceSerifPro-Bold.ttf') format('truetype'); +} + +@font-face{ + font-family: 'Source Serif Pro'; + font-weight: 900; + font-style: normal; + font-stretch: normal; + src: url('EOT/SourceSerifPro-Black.eot') format('embedded-opentype'), + url('WOFF/OTF/SourceSerifPro-Black.otf.woff') format('woff'), + url('OTF/SourceSerifPro-Black.otf') format('opentype'), + url('TTF/SourceSerifPro-Black.ttf') format('truetype'); +} diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/guzzle.css_t b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/guzzle.css_t @@ -0,0 +1,1037 @@ +/* Sphinx themes +-------------------------------------------------- */ + +body { + background-color: #edf0f2; + margin: 0; + padding: 0; + font-family: "Open Sans", Helvetica, Arial, sans-serif; + font-size: 16px; + color: #333; + line-height: 1.5; +} + +#left-column { + float: left; + position: fixed; + height: 100%; + border-right: 1px solid #e0e0e0; + width: 300px; + overflow: auto; + background: #fafafa; +} + +#right-column { + padding: 20px 0; + margin-left: 300px; + background-color: #fff; +} + +a.headerlink { + visibility: hidden; + color: #ddd; + padding: 0 4px; + text-decoration: none; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +h1 > a, h2 > a, h3 > a, h4 > a, h5 > a, h6 > a { + color: #5C7C98; +} + +h1, h2, h3, h4, h5, h6 { + color: black; + font-weight: normal; + padding: 0; + font-family: "Source Serif Pro", "serif"; +} + +h1, h2, h3 { + margin-top: 30px; + margin-bottom: 20px; +} + +h1 { + font-size: 38px; + padding: 10px 10px 10px 45px; + margin: 20px 0 35px -45px; + background-color: aliceblue; + width: calc(100% + 90px); + border-bottom: 1px solid #D8E4EF; +} + +h2 { + font-size: 34px; + padding: .2em 0; + border-bottom: 1px solid #ddd; +} + +h3 { + margin-top: 35px; + font-size: 28px; +} + +h4 { + margin-top: 30px; + font-size: 24px; +} + +h5 { + margin-top: 25px; + font-size: 20px; +} + +div.clearer { + clear: both; +} + +.container-wrapper { + padding: 0; + position: relative; +} + +div.related { + display: none; +} + +p { + padding: 0; + font-family: inherit; + font-size: inherit; + color: #333; +} + +code, pre, tt { + font-size: 15px; + font-family: Consolas, monospace; +} + +code, tt { + color: #8D1A38; +} + +tt { + padding: 0 2px; +} + +code, pre { + line-height: 23px; + margin: 20px 0; + word-wrap: normal; + background-color: #fff; +} + +pre { + color: #333; + background-color: #fff; + overflow: auto; + border-width: 0 0 0 2px; + border-color: #eee; + border-style: solid; + padding: 14px 0 14px 20px; + padding-right: 0; + margin: 20px 0; +} + +div.highlight { + background-color: white; +} + +a.internal em { + font-style: normal; +} + +dl dd { + margin: 3px 0 10px 30px; +} + +dl.method { + border-bottom: 1px solid #ccc; +} + +.breadcrumb { + font-size: 15px; + margin-bottom: 12px; + background: #fff; +} + +blockquote { + border-width: .1em 0 .1em 0; + border-color: #e5eef2; + border-style: solid; + background-color: #f3f8f9; + color: #000; + margin: 20px 0; + padding: 15px 20px; + font-size: 16px; +} + +/* Sphinx sidebar +-------------------------------------------------- */ + +div.sphinxsidebar { + word-wrap: break-word; +} + +div.sphinxsidebar .panel-default > .panel-heading { + background-image: none; +} + +.sidebar-wrapper { + padding: 0 22px; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + color: #444; + font-size: 20px; + font-weight: normal; + margin: 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 16px; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +.sidebar-toc { + font-size: 15px; +} + +div.sphinxsidebar .sidebar-toc ul { + margin: 0 0 4px 0; + list-style-type: none; + color: #000; +} + +div.sphinxsidebar .sidebar-toc a { + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + color: #444; + text-decoration: none; +} + +.sidebar-toc > ul { + padding: 0 !important; + list-style-type: none; + margin: 0; +} + +.sidebar-toc ul li a { + display: block; +} + +.sidebar-toc ul li a:hover { + background-color: #428bca; + color: #fff; +} + +.sidebar-toc ul li.current > a, +.sidebar-toc ul li.current > a:hover { + background-color: #e6e6e6; + color: #444; +} + +.sidebar-toc ul li.toctree-l1 a { + padding: 5px 25px; +} + +.sidebar-toc ul li.toctree-l2 a { + padding: 5px 50px; +} + +.sidebar-toc ul li.toctree-l3 a { + padding: 5px 75px; +} + +div.sphinxsidebar ul.want-points { + padding-left: 20px; + margin: 0; +} + +div.sphinxsidebar .sidebar-toc ul ul { + margin: 0; + padding: 0; +} + +.sidebar-localtoc ul { + padding-left: 24px; +} + +div.sphinxsidebar input { + border: 1px solid #ccc; + font-family: Helvetica, arial, freesans, clean, sans-serif; + font-size: 1em; +} + +.margin-top-1em { + margin-top: 1em; +} + +.sidebar-block { + padding: 0; + margin: 14px 0 30px 0; +} + +.sidebar-block h2 { + border-bottom: none; + margin: 0 0 17px 0; + font-size: 14px; + font-family: "Open Sans", Helvetica, Arial, sans-serif; + padding: 0 0 6px 0; + font-weight: bold; + text-transform: uppercase; + color: #606060; +} + +.sidebar-block .bd { + font-size: 16px; +} + +.sphinxsidebar > .sidebar-block:not(:last-child):after { + content: ''; + display:block; + border-top: 1px solid #ccc; + margin: 24px 22px 0 22px; +} + +.text-logo { + font-size: 18px; + text-align: center; + display: block; + padding: 8px; + color: #fff; + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + margin: 0 0 20px 0; + font-weight: bold; + background-color: #337ab7; + border-bottom: 1px solid #fff; +} + +.text-logo:hover { + color: #fff; +} + +/* Left-nav search box +-------------------------------------------------- */ + +#main-search form .input-group { + width: 100%; + margin: 0 0 12px 0; + padding: 0; + border: none; +} + +#main-search form .input-group input { + padding: 4px; + width: 100%; + border-radius: 5px; + margin: 0; + font-size: 15px; +} + +.search-page-form { + width: 350px; +} + +/* Two-pane table list +-------------------------------------------------- */ + +.table-bordered>thead>tr>th, +.table-bordered>tbody>tr>th, +.table-bordered>tfoot>tr>th, +.table-bordered>thead>tr>td, +.table-bordered>tbody>tr>td, +.table-bordered>tfoot>tr>td, +table.two-column.table-bordered caption+thead tr:first-child th:first-child, +table.two-column.table-bordered caption+tbody tr:first-child td:first-child, +table.two-column.table-bordered colgroup+thead tr:first-child th:first-child, +table.two-column.table-bordered colgroup+tbody tr:first-child td:first-child, +table.two-column tbody td + border: 0 0 1px 0 solid #eee; + border-left: none; + padding: 8px 4px; + font-size: 16px; +} + +table.two-column { + width: 100%; + border: 0px none !important; + box-shadow: none; +} + +/* Disqus comments styles +-------------------------------------------------- */ + +.comment-container { + margin: 24px auto; +} + +/* Next and previous links +-------------------------------------------------- */ + +.footer-relations { + display: relative; + border-top: 1px solid #ccc; + padding: 12px 45px; + margin-top: 30px; + font-size: 24px; +} + +.rel-spacer { + height: 40px; +} + +/* Footer styling +-------------------------------------------------- */ + +div.footer { + padding: 25px; + font-size: 14px; + color: #888; + text-align: right; + max-width: 1200px; + width: 100%; +} + +div.footer a { + color: #888; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background: url(file.png) no-repeat 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- general index --------------------------------------------------------- */ + +table { + margin-bottom: 20px; +} + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable dl, table.indextable dd { + margin-top: 0; + margin-bottom: 0; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- general body styles --------------------------------------------------- */ + +.body { + padding: 0 45px; +} + +div.body p.caption { + text-align: inherit; +} + +table.field-list { + border: 1px solid #ddd; + border-collapse: collapse; + border-spacing: 0; + width: 100%; +} + +table.field-list td, +table.field-list th { + border: 1px solid #ddd; + padding: 8px; + vertical-align: top; + line-height: 1.4; +} + +.field-list ul { + padding-left: 1em; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #e8e8e8; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; + background-color: #f8f8f8; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- contents-------------------------------------------------------------- */ + +div.topic.contents { + display: inline-block; + border-radius: 3px; + padding: 24px 36px 18px 36px; +} + +div.topic.contents > ul { + padding-left: 20px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +.admonition { + margin: 20px 0; + padding: 20px; + background-color: #fff; + border: 1px solid #eee; + border-left-width: 6px; + border-radius: 3px; +} + +.admonition dt { + font-weight: bold; +} + +.admonition dl { + margin-bottom: 0; +} + +.admonition-title { + margin: 0px 0 5px; + padding: 0; + font-weight: bold; + font-size: 18px; + line-height: 1.1; + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +.admonition.danger, +.admonition.error { + border-left-color: #d9534f; +} + +.admonition.danger .admonition-title, +.admonition.error .admonition-title { + color: #d9534f; +} + +.admonition.important, +.admonition.warning, +.admonition.attention, +.admonition.caution { + border-left-color: #f0ad4e; +} + +.admonition.important .admonition-title, +.admonition.warning .admonition-title, +.admonition.attention .admonition-title, +.admonition.caution .admonition-title { + color: #9B581F; +} + +.admonition.note, +.admonition.hint { + border-left-color: #31708f; +} + +.admonition.note .admonition-title, +.admonition.hint .admonition-title { + color: #31708f; +} + +.admonition.tip { + border-left-color: #3c763d; +} + +.admonition.tip .admonition-title { + color: #3c763d; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.admonition tt.xref, div.admonition a tt { + border-bottom: 1px solid #fafafa; +} + +div.admonition p.last { + margin-bottom: 0; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +.highlighted { + background-color: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.refcount { + color: #060; +} + +.optional { + font-size: 1.3em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +/* -- code displays --------------------------------------------------------- */ + +.code-block-caption { + margin-bottom: -20px; +} + +.code-block-caption .caption-text { + display: inline-block; + padding: 6px 20px; + font-weight: bold; + font-size: 18px; + line-height: 1.1; + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + color: #fff; + background-color: #337ab7; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +tt.descname { + background-color: transparent; + font-weight: bold; + padding-right: 0.08em; +} + +tt.descclassname { + background-color: transparent; +} + +tt.descname, tt.descclassname { + font-size: 0.95em; +} + +tt.xref, a tt { + background-color: transparent; + font-weight: bold; +} + +h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +/* -- Theme specific classes - */ + +.overflow-height-500px { + overflow: auto; + height: 500px; +} + +.overflow-height-250px { + overflow: auto; + height: 250px; +} + +/* Toggle mobile view +-------------------------------------------------- */ + +#mobile-toggle { + height: 40px; + width: 100%; + display: none; + padding: 12px; + border-bottom: 1px solid #ccc; + position: fixed; + top: 0; + left: 0; + background-color: #fff; + z-index: 1; +} + +/* Small screen styles +-------------------------------------------------- */ + +@media screen and (max-width: 768px) { + + body { + padding: 0px; + margin: 0px; + background-color: #fff; + } + + h1 { + margin-left: 0; + width: 100%; + padding: 10px; + font-size: 40px; + } + + #left-column { + position: relative; + top: 0; + left: 0; + display: none; + width: 100%; + float: none; + margin: 40px 0 0 0; + } + + .footer-relations { + padding: 12px 0; + } + + #right-column { + margin-left: 0; + margin-top: 0; + padding: 50px 20px 8px 20px; + width: 100%; + float: none; + } + + .document { + position: relative; + padding: 0; + width: 100% + } + + .body { + padding: 0px; + } + + #mobile-toggle { + display: block; + } + + p { + padding: 0; + } +} + +/* Account for when the left column is closed then page is expanded. +-------------------------------------------------- */ + +@media screen and (min-width: 769px) { + #left-column { + display: block !important; + } + div.footer { + margin-left: 300px; + } +} + +/* Syntax highlighting +-------------------------------------------------- */ + +.hll { background-color: #ffffcc } +.c { color: #999988; font-style: italic } /* Comment */ +.err { color: #a61717; background-color: #e3d2d2 } /* Error */ +.k { color: #000000; font-weight: bold } /* Keyword */ +.o { color: #000000; font-weight: bold } /* Operator */ +.cm { color: #999988; font-style: italic } /* Comment.Multiline */ +.cp { color: #999999; font-weight: bold; font-style: italic } /* Comment.Preproc */ +.c1 { color: #999988; font-style: italic } /* Comment.Single */ +.cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ +.gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ +.ge { color: #000000; font-style: italic } /* Generic.Emph */ +.gr { color: #aa0000 } /* Generic.Error */ +.gh { color: #999999 } /* Generic.Heading */ +.gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ +.go { color: #888888 } /* Generic.Output */ +.gp { color: #555555 } /* Generic.Prompt */ +.gs { font-weight: bold } /* Generic.Strong */ +.gu { color: #aaaaaa } /* Generic.Subheading */ +.gt { color: #aa0000 } /* Generic.Traceback */ +.kc { color: #000000; font-weight: bold } /* Keyword.Constant */ +.kd { color: #000000; font-weight: bold } /* Keyword.Declaration */ +.kn { color: #000000; font-weight: bold } /* Keyword.Namespace */ +.kp { color: #000000; font-weight: bold } /* Keyword.Pseudo */ +.kr { color: #000000; font-weight: bold } /* Keyword.Reserved */ +.kt { color: #445588; font-weight: bold } /* Keyword.Type */ +.m { color: #009999 } /* Literal.Number */ +.s { color: #d01040 } /* Literal.String */ +.na { color: #008080 } /* Name.Attribute */ +.nb { color: #0086B3 } /* Name.Builtin */ +.nc { color: #445588; font-weight: bold } /* Name.Class */ +.no { color: #008080 } /* Name.Constant */ +.nd { color: #3c5d5d; font-weight: bold } /* Name.Decorator */ +.ni { color: #800080 } /* Name.Entity */ +.ne { color: #990000; font-weight: bold } /* Name.Exception */ +.nf { color: #990000; font-weight: bold } /* Name.Function */ +.nl { color: #990000; font-weight: bold } /* Name.Label */ +.nn { color: #555555 } /* Name.Namespace */ +.nt { color: #000080 } /* Name.Tag */ +.nv { color: #008080 } /* Name.Variable */ +.ow { color: #000000; font-weight: bold } /* Operator.Word */ +.w { color: #bbbbbb } /* Text.Whitespace */ +.mf { color: #009999 } /* Literal.Number.Float */ +.mh { color: #009999 } /* Literal.Number.Hex */ +.mi { color: #009999 } /* Literal.Number.Integer */ +.mo { color: #009999 } /* Literal.Number.Oct */ +.mn { color: #009999 } /* Literal.Number.Number */ +.mrow { color: #009999 } /* Literal.Number.Row */ +.sb { color: #d01040 } /* Literal.String.Backtick */ +.sc { color: #d01040 } /* Literal.String.Char */ +.sd { color: #d01040 } /* Literal.String.Doc */ +.s2 { color: #d01040 } /* Literal.String.Double */ +.se { color: #d01040 } /* Literal.String.Escape */ +.sh { color: #d01040 } /* Literal.String.Heredoc */ +.si { color: #d01040 } /* Literal.String.Interpol */ +.sx { color: #d01040 } /* Literal.String.Other */ +.sr { color: #009926 } /* Literal.String.Regex */ +.s1 { color: #d01040 } /* Literal.String.Single */ +.ss { color: #990073 } /* Literal.String.Symbol */ +.bp { color: #999999 } /* Name.Builtin.Pseudo */ +.vc { color: #008080 } /* Name.Variable.Class */ +.vg { color: #008080 } /* Name.Variable.Global */ +.vi { color: #008080 } /* Name.Variable.Instance */ +.il { color: #009999 } /* Literal.Number.Integer.Long */ diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/jquery.js b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/jquery.js @@ -0,0 +1,5 @@ +/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license + //@ sourceMappingURL=jquery.min.map + */(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:v&&!v.call("\ufeff\u00a0")?function(e){return null==e?"":v.call(e)}:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?b.merge(n,"string"==typeof e?[e]:e):d.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(g)return g.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return f.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),b.isFunction(e)?(r=h.call(arguments,2),i=function(){return e.apply(n||this,r.concat(h.call(arguments)))},i.guid=e.guid=e.guid||b.guid++,i):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===b.type(r)){o=!0;for(u in r)b.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,b.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(b(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),b.ready.promise=function(t){if(!n)if(n=b.Deferred(),"complete"===o.readyState)setTimeout(b.ready);else if(o.addEventListener)o.addEventListener("DOMContentLoaded",H,!1),e.addEventListener("load",H,!1);else{o.attachEvent("onreadystatechange",H),e.attachEvent("onload",H);var r=!1;try{r=null==e.frameElement&&o.documentElement}catch(i){}r&&r.doScroll&&function a(){if(!b.isReady){try{r.doScroll("left")}catch(e){return setTimeout(a,50)}q(),b.ready()}}()}return n.promise(t)},b.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=b.type(e);return b.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=b(o);var _={};function F(e){var t=_[e]={};return b.each(e.match(w)||[],function(e,n){t[n]=!0}),t}b.Callbacks=function(e){e="string"==typeof e?_[e]||F(e):b.extend({},e);var n,r,i,o,a,s,u=[],l=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=u.length,n=!0;u&&o>a;a++)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,u&&(l?l.length&&c(l.shift()):r?u=[]:p.disable())},p={add:function(){if(u){var t=u.length;(function i(t){b.each(t,function(t,n){var r=b.type(n);"function"===r?e.unique&&p.has(n)||u.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=u.length:r&&(s=t,c(r))}return this},remove:function(){return u&&b.each(arguments,function(e,t){var r;while((r=b.inArray(t,u,r))>-1)u.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?b.inArray(e,u)>-1:!(!u||!u.length)},empty:function(){return u=[],this},disable:function(){return u=l=r=t,this},disabled:function(){return!u},lock:function(){return l=t,r||p.disable(),this},locked:function(){return!l},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!u||i&&!l||(n?l.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},b.extend({Deferred:function(e){var t=[["resolve","done",b.Callbacks("once memory"),"resolved"],["reject","fail",b.Callbacks("once memory"),"rejected"],["notify","progress",b.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return b.Deferred(function(n){b.each(t,function(t,o){var a=o[0],s=b.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&b.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?b.extend(e,r):r}},i={};return r.pipe=r.then,b.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=h.call(arguments),r=n.length,i=1!==r||e&&b.isFunction(e.promise)?r:0,o=1===i?e:b.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?h.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,u,l;if(r>1)for(s=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&b.isFunction(n[t].promise)?n[t].promise().done(a(t,l,n)).fail(o.reject).progress(a(t,u,s)):--i;return i||o.resolveWith(l,n),o.promise()}}),b.support=function(){var t,n,r,a,s,u,l,c,p,f,d=o.createElement("div");if(d.setAttribute("className","t"),d.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*"),r=d.getElementsByTagName("a")[0],!n||!r||!n.length)return{};s=o.createElement("select"),l=s.appendChild(o.createElement("option")),a=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={getSetAttribute:"t"!==d.className,leadingWhitespace:3===d.firstChild.nodeType,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:"/a"===r.getAttribute("href"),opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:!!a.value,optSelected:l.selected,enctype:!!o.createElement("form").enctype,html5Clone:"<:nav></:nav>"!==o.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===o.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},a.checked=!0,t.noCloneChecked=a.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!l.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}a=o.createElement("input"),a.setAttribute("value",""),t.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),t.radioValue="t"===a.value,a.setAttribute("checked","t"),a.setAttribute("name","t"),u=o.createDocumentFragment(),u.appendChild(a),t.appendChecked=a.checked,t.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;return d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip,b(function(){var n,r,a,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",u=o.getElementsByTagName("body")[0];u&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",u.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",a=d.getElementsByTagName("td"),a[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===a[0].offsetHeight,a[0].style.display="",a[1].style.display="none",t.reliableHiddenOffsets=p&&0===a[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=4===d.offsetWidth,t.doesNotIncludeMarginInBodyOffset=1!==u.offsetTop,e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(o.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(u.style.zoom=1)),u.removeChild(n),n=d=a=r=null)}),n=s=u=l=r=a=null,t}();var O=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,B=/([A-Z])/g;function P(e,n,r,i){if(b.acceptData(e)){var o,a,s=b.expando,u="string"==typeof n,l=e.nodeType,p=l?b.cache:e,f=l?e[s]:e[s]&&s;if(f&&p[f]&&(i||p[f].data)||!u||r!==t)return f||(l?e[s]=f=c.pop()||b.guid++:f=s),p[f]||(p[f]={},l||(p[f].toJSON=b.noop)),("object"==typeof n||"function"==typeof n)&&(i?p[f]=b.extend(p[f],n):p[f].data=b.extend(p[f].data,n)),o=p[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[b.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[b.camelCase(n)])):a=o,a}}function R(e,t,n){if(b.acceptData(e)){var r,i,o,a=e.nodeType,s=a?b.cache:e,u=a?e[b.expando]:b.expando;if(s[u]){if(t&&(o=n?s[u]:s[u].data)){b.isArray(t)?t=t.concat(b.map(t,b.camelCase)):t in o?t=[t]:(t=b.camelCase(t),t=t in o?[t]:t.split(" "));for(r=0,i=t.length;i>r;r++)delete o[t[r]];if(!(n?$:b.isEmptyObject)(o))return}(n||(delete s[u].data,$(s[u])))&&(a?b.cleanData([e],!0):b.support.deleteExpando||s!=s.window?delete s[u]:s[u]=null)}}}b.extend({cache:{},expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?b.cache[e[b.expando]]:e[b.expando],!!e&&!$(e)},data:function(e,t,n){return P(e,t,n)},removeData:function(e,t){return R(e,t)},_data:function(e,t,n){return P(e,t,n,!0)},_removeData:function(e,t){return R(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&b.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),b.fn.extend({data:function(e,n){var r,i,o=this[0],a=0,s=null;if(e===t){if(this.length&&(s=b.data(o),1===o.nodeType&&!b._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>a;a++)i=r[a].name,i.indexOf("data-")||(i=b.camelCase(i.slice(5)),W(o,i,s[i]));b._data(o,"parsedAttrs",!0)}return s}return"object"==typeof e?this.each(function(){b.data(this,e)}):b.access(this,function(n){return n===t?o?W(o,e,b.data(o,e)):null:(this.each(function(){b.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){b.removeData(this,e)})}});function W(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(B,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:O.test(r)?b.parseJSON(r):r}catch(o){}b.data(e,n,r)}else r=t}return r}function $(e){var t;for(t in e)if(("data"!==t||!b.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}b.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=b._data(e,n),r&&(!i||b.isArray(r)?i=b._data(e,n,b.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=b.queue(e,t),r=n.length,i=n.shift(),o=b._queueHooks(e,t),a=function(){b.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return b._data(e,n)||b._data(e,n,{empty:b.Callbacks("once memory").add(function(){b._removeData(e,t+"queue"),b._removeData(e,n)})})}}),b.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?b.queue(this[0],e):n===t?this:this.each(function(){var t=b.queue(this,e,n);b._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&b.dequeue(this,e)})},dequeue:function(e){return this.each(function(){b.dequeue(this,e)})},delay:function(e,t){return e=b.fx?b.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=b.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=b._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var I,z,X=/[\t\r\n]/g,U=/\r/g,V=/^(?:input|select|textarea|button|object)$/i,Y=/^(?:a|area)$/i,J=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,G=/^(?:checked|selected)$/i,Q=b.support.getSetAttribute,K=b.support.input;b.fn.extend({attr:function(e,t){return b.access(this,b.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,t){return b.access(this,b.prop,e,t,arguments.length>1)},removeProp:function(e){return e=b.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=b.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?b.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return b.isFunction(e)?this.each(function(n){b(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=b(this),u=t,l=e.match(w)||[];while(o=l[a++])u=r?u:!s.hasClass(o),s[u?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&b._data(this,"__className__",this.className),this.className=this.className||e===!1?"":b._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(X," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=b.isFunction(e),this.each(function(n){var o,a=b(this);1===this.nodeType&&(o=i?e.call(this,n,a.val()):e,null==o?o="":"number"==typeof o?o+="":b.isArray(o)&&(o=b.map(o,function(e){return null==e?"":e+""})),r=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=b.valHooks[o.type]||b.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(U,""):null==n?"":n)}}}),b.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;for(;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(b.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&b.nodeName(n.parentNode,"optgroup"))){if(t=b(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n=b.makeArray(t);return b(e).find("option").each(function(){this.selected=b.inArray(b(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var o,a,s,u=e.nodeType;if(e&&3!==u&&8!==u&&2!==u)return typeof e.getAttribute===i?b.prop(e,n,r):(a=1!==u||!b.isXMLDoc(e),a&&(n=n.toLowerCase(),o=b.attrHooks[n]||(J.test(n)?z:I)),r===t?o&&a&&"get"in o&&null!==(s=o.get(e,n))?s:(typeof e.getAttribute!==i&&(s=e.getAttribute(n)),null==s?t:s):null!==r?o&&a&&"set"in o&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r):(b.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=b.propFix[n]||n,J.test(n)?!Q&&G.test(n)?e[b.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:b.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!b.support.radioValue&&"radio"===t&&b.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!b.isXMLDoc(e),a&&(n=b.propFix[n]||n,o=b.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):V.test(e.nodeName)||Y.test(e.nodeName)&&e.href?0:t}}}}),z={get:function(e,n){var r=b.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?K&&Q?null!=i:G.test(n)?e[b.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?b.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&b.propFix[n]||n,n):e[b.camelCase("default-"+n)]=e[n]=!0,n}},K&&Q||(b.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return b.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t},set:function(e,n,r){return b.nodeName(e,"input")?(e.defaultValue=n,t):I&&I.set(e,n,r)}}),Q||(I=b.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},b.attrHooks.contenteditable={get:I.get,set:function(e,t,n){I.set(e,""===t?!1:t,n)}},b.each(["width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),b.support.hrefNormalized||(b.each(["href","src","width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return null==r?t:r}})}),b.each(["href","src"],function(e,t){b.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),b.support.style||(b.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),b.support.optSelected||(b.propHooks.selected=b.extend(b.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),b.support.enctype||(b.propFix.enctype="encoding"),b.support.checkOn||b.each(["radio","checkbox"],function(){b.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),b.each(["radio","checkbox"],function(){b.valHooks[this]=b.extend(b.valHooks[this],{set:function(e,n){return b.isArray(n)?e.checked=b.inArray(b(e).val(),n)>=0:t}})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}b.event={global:{},add:function(e,n,r,o,a){var s,u,l,c,p,f,d,h,g,m,y,v=b._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=b.guid++),(u=v.events)||(u=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof b===i||e&&b.event.triggered===e.type?t:b.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(w)||[""],l=n.length;while(l--)s=rt.exec(n[l])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),p=b.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=b.event.special[g]||{},d=b.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&b.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=u[g])||(h=u[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),b.event.global[g]=!0;e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,p,f,d,h,g,m=b.hasData(e)&&b._data(e);if(m&&(c=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(s=rt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=b.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),u=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));u&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||b.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)b.event.remove(e,d+t[l],n,r,!0);b.isEmptyObject(c)&&(delete m.handle,b._removeData(e,"events"))}},trigger:function(n,r,i,a){var s,u,l,c,p,f,d,h=[i||o],g=y.call(n,"type")?n.type:n,m=y.call(n,"namespace")?n.namespace.split("."):[];if(l=f=i=i||o,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+b.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),u=0>g.indexOf(":")&&"on"+g,n=n[b.expando]?n:new b.Event(g,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:b.makeArray(r,[n]),p=b.event.special[g]||{},a||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!a&&!p.noBubble&&!b.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(l=l.parentNode);l;l=l.parentNode)h.push(l),f=l;f===(i.ownerDocument||o)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((l=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(b._data(l,"events")||{})[n.type]&&b._data(l,"handle"),s&&s.apply(l,r),s=u&&l[u],s&&b.acceptData(l)&&s.apply&&s.apply(l,r)===!1&&n.preventDefault();if(n.type=g,!(a||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===g&&b.nodeName(i,"a")||!b.acceptData(i)||!u||!i[g]||b.isWindow(i))){f=i[u],f&&(i[u]=null),b.event.triggered=g;try{i[g]()}catch(v){}b.event.triggered=t,f&&(i[u]=f)}return n.result}},dispatch:function(e){e=b.event.fix(e);var n,r,i,o,a,s=[],u=h.call(arguments),l=(b._data(this,"events")||{})[e.type]||[],c=b.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=b.event.handlers.call(this,e,l),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((b.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,u),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(1===l.nodeType&&(l.disabled!==!0||"click"!==e.type)){for(o=[],a=0;u>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?b(r,this).index(l)>=0:b.find(r,this,null,[l]).length),o[r]&&o.push(i);o.length&&s.push({elem:l,handlers:o})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[b.expando])return e;var t,n,r,i=e.type,a=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new b.Event(a),t=r.length;while(t--)n=r[t],e[n]=a[n];return e.target||(e.target=a.srcElement||o),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,a):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,a,s=n.button,u=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||o,a=i.documentElement,r=i.body,e.pageX=n.clientX+(a&&a.scrollLeft||r&&r.scrollLeft||0)-(a&&a.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(a&&a.scrollTop||r&&r.scrollTop||0)-(a&&a.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&u&&(e.relatedTarget=u===e.target?n.toElement:u),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return b.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==o.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===o.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=b.extend(new b.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?b.event.trigger(i,null,t):b.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},b.removeEvent=o.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},b.Event=function(e,n){return this instanceof b.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&b.extend(this,n),this.timeStamp=e&&e.timeStamp||b.now(),this[b.expando]=!0,t):new b.Event(e,n)},b.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},b.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){b.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj; + return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>i.cacheLength&&delete e[t.shift()],e[n]=r}}function ot(e){return e[x]=!0,e}function at(e){var t=p.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function st(e,t,n,r){var i,o,a,s,u,l,f,g,m,v;if((t?t.ownerDocument||t:w)!==p&&c(t),t=t||p,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!d&&!r){if(i=J.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&y(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return H.apply(n,q.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&T.getByClassName&&t.getElementsByClassName)return H.apply(n,q.call(t.getElementsByClassName(a),0)),n}if(T.qsa&&!h.test(e)){if(f=!0,g=x,m=t,v=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){l=ft(e),(f=t.getAttribute("id"))?g=f.replace(K,"\\$&"):t.setAttribute("id",g),g="[id='"+g+"'] ",u=l.length;while(u--)l[u]=g+dt(l[u]);m=V.test(e)&&t.parentNode||t,v=l.join(",")}if(v)try{return H.apply(n,q.call(m.querySelectorAll(v),0)),n}catch(b){}finally{f||t.removeAttribute("id")}}}return wt(e.replace(W,"$1"),t,n,r)}a=st.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},c=st.setDocument=function(e){var n=e?e.ownerDocument||e:w;return n!==p&&9===n.nodeType&&n.documentElement?(p=n,f=n.documentElement,d=a(n),T.tagNameNoComments=at(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),T.attributes=at(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),T.getByClassName=at(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),T.getByName=at(function(e){e.id=x+0,e.innerHTML="<a name='"+x+"'></a><div name='"+x+"'></div>",f.insertBefore(e,f.firstChild);var t=n.getElementsByName&&n.getElementsByName(x).length===2+n.getElementsByName(x+0).length;return T.getIdNotName=!n.getElementById(x),f.removeChild(e),t}),i.attrHandle=at(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==A&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},T.getIdNotName?(i.find.ID=function(e,t){if(typeof t.getElementById!==A&&!d){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){return e.getAttribute("id")===t}}):(i.find.ID=function(e,n){if(typeof n.getElementById!==A&&!d){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==A&&r.getAttributeNode("id").value===e?[r]:t:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){var n=typeof e.getAttributeNode!==A&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=T.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==A?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.NAME=T.getByName&&function(e,n){return typeof n.getElementsByName!==A?n.getElementsByName(name):t},i.find.CLASS=T.getByClassName&&function(e,n){return typeof n.getElementsByClassName===A||d?t:n.getElementsByClassName(e)},g=[],h=[":focus"],(T.qsa=rt(n.querySelectorAll))&&(at(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||h.push("\\["+_+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){e.innerHTML="<input type='hidden' i=''/>",e.querySelectorAll("[i^='']").length&&h.push("[*^$]="+_+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(T.matchesSelector=rt(m=f.matchesSelector||f.mozMatchesSelector||f.webkitMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){T.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",R)}),h=RegExp(h.join("|")),g=RegExp(g.join("|")),y=rt(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},v=f.compareDocumentPosition?function(e,t){var r;return e===t?(u=!0,0):(r=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&r||e.parentNode&&11===e.parentNode.nodeType?e===n||y(w,e)?-1:t===n||y(w,t)?1:0:4&r?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return u=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:0;if(o===a)return ut(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?ut(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},u=!1,[0,0].sort(v),T.detectDuplicates=u,p):p},st.matches=function(e,t){return st(e,null,null,t)},st.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Z,"='$1']"),!(!T.matchesSelector||d||g&&g.test(t)||h.test(t)))try{var n=m.call(e,t);if(n||T.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return st(t,p,null,[e]).length>0},st.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},st.attr=function(e,t){var n;return(e.ownerDocument||e)!==p&&c(e),d||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):d||T.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},st.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},st.uniqueSort=function(e){var t,n=[],r=1,i=0;if(u=!T.detectDuplicates,e.sort(v),u){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e};function ut(e,t){var n=t&&e,r=n&&(~t.sourceIndex||j)-(~e.sourceIndex||j);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function lt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ct(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function pt(e){return ot(function(t){return t=+t,ot(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}o=st.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=st.selectors={cacheLength:50,createPseudo:ot,match:U,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(et,tt),e[3]=(e[4]||e[5]||"").replace(et,tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||st.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&st.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return U.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&z.test(n)&&(t=ft(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(et,tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[e+" "];return t||(t=RegExp("(^|"+_+")"+e+"("+_+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==A&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=st.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[x]||(m[x]={}),l=c[e]||[],d=l[0]===N&&l[1],f=l[0]===N&&l[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[N,d,f];break}}else if(v&&(l=(t[x]||(t[x]={}))[e])&&l[0]===N)f=l[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[x]||(p[x]={}))[e]=[N,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||st.error("unsupported pseudo: "+e);return r[x]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ot(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=M.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ot(function(e){var t=[],n=[],r=s(e.replace(W,"$1"));return r[x]?ot(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ot(function(e){return function(t){return st(e,t).length>0}}),contains:ot(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ot(function(e){return X.test(e||"")||st.error("unsupported lang: "+e),e=e.replace(et,tt).toLowerCase(),function(t){var n;do if(n=d?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:pt(function(){return[0]}),last:pt(function(e,t){return[t-1]}),eq:pt(function(e,t,n){return[0>n?n+t:n]}),even:pt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:pt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:pt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:pt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[n]=lt(n);for(n in{submit:!0,reset:!0})i.pseudos[n]=ct(n);function ft(e,t){var n,r,o,a,s,u,l,c=E[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=i.preFilter;while(s){(!n||(r=$.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(o=[])),n=!1,(r=I.exec(s))&&(n=r.shift(),o.push({value:n,type:r[0].replace(W," ")}),s=s.slice(n.length));for(a in i.filter)!(r=U[a].exec(s))||l[a]&&!(r=l[a](r))||(n=r.shift(),o.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?st.error(e):E(e,u).slice(0)}function dt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function ht(e,t,n){var i=t.dir,o=n&&"parentNode"===i,a=C++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,s){var u,l,c,p=N+" "+a;if(s){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[x]||(t[x]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,s)||r,l[1]===!0)return!0}}function gt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function mt(e,t,n,r,i){var o,a=[],s=0,u=e.length,l=null!=t;for(;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function yt(e,t,n,r,i,o){return r&&!r[x]&&(r=yt(r)),i&&!i[x]&&(i=yt(i,o)),ot(function(o,a,s,u){var l,c,p,f=[],d=[],h=a.length,g=o||xt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:mt(g,f,e,s,u),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,u),r){l=mt(y,d),r(l,[],s,u),c=l.length;while(c--)(p=l[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?M.call(o,p):f[c])>-1&&(o[l]=!(a[l]=p))}}else y=mt(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):H.apply(a,y)})}function vt(e){var t,n,r,o=e.length,a=i.relative[e[0].type],s=a||i.relative[" "],u=a?1:0,c=ht(function(e){return e===t},s,!0),p=ht(function(e){return M.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>u;u++)if(n=i.relative[e[u].type])f=[ht(gt(f),n)];else{if(n=i.filter[e[u].type].apply(null,e[u].matches),n[x]){for(r=++u;o>r;r++)if(i.relative[e[r].type])break;return yt(u>1&&gt(f),u>1&&dt(e.slice(0,u-1)).replace(W,"$1"),n,r>u&&vt(e.slice(u,r)),o>r&&vt(e=e.slice(r)),o>r&&dt(e))}f.push(n)}return gt(f)}function bt(e,t){var n=0,o=t.length>0,a=e.length>0,s=function(s,u,c,f,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,T=l,C=s||a&&i.find.TAG("*",d&&u.parentNode||u),k=N+=null==T?1:Math.random()||.1;for(w&&(l=u!==p&&u,r=n);null!=(h=C[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,u,c)){f.push(h);break}w&&(N=k,r=++n)}o&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,o&&b!==v){g=0;while(m=t[g++])m(x,y,u,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=L.call(f));y=mt(y)}H.apply(f,y),w&&!s&&y.length>0&&v+t.length>1&&st.uniqueSort(f)}return w&&(N=k,l=T),x};return o?ot(s):s}s=st.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=ft(e)),n=t.length;while(n--)o=vt(t[n]),o[x]?r.push(o):i.push(o);o=S(e,bt(i,r))}return o};function xt(e,t,n){var r=0,i=t.length;for(;i>r;r++)st(e,t[r],n);return n}function wt(e,t,n,r){var o,a,u,l,c,p=ft(e);if(!r&&1===p.length){if(a=p[0]=p[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&!d&&i.relative[a[1].type]){if(t=i.find.ID(u.matches[0].replace(et,tt),t)[0],!t)return n;e=e.slice(a.shift().value.length)}o=U.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],i.relative[l=u.type])break;if((c=i.find[l])&&(r=c(u.matches[0].replace(et,tt),V.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=r.length&&dt(a),!e)return H.apply(n,q.call(r,0)),n;break}}}return s(e,p)(r,t,d,n,V.test(e)),n}i.pseudos.nth=i.pseudos.eq;function Tt(){}i.filters=Tt.prototype=i.pseudos,i.setFilters=new Tt,c(),st.attr=b.attr,b.find=st,b.expr=st.selectors,b.expr[":"]=b.expr.pseudos,b.unique=st.uniqueSort,b.text=st.getText,b.isXMLDoc=st.isXML,b.contains=st.contains}(e);var at=/Until$/,st=/^(?:parents|prev(?:Until|All))/,ut=/^.[^:#\[\.,]*$/,lt=b.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};b.fn.extend({find:function(e){var t,n,r,i=this.length;if("string"!=typeof e)return r=this,this.pushStack(b(e).filter(function(){for(t=0;i>t;t++)if(b.contains(r[t],this))return!0}));for(n=[],t=0;i>t;t++)b.find(e,this[t],n);return n=this.pushStack(i>1?b.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=b(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(b.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1))},filter:function(e){return this.pushStack(ft(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?lt.test(e)?b(e,this.context).index(this[0])>=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],a=lt.test(e)||"string"!=typeof e?b(e,t||this.context):0;for(;i>r;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&11!==n.nodeType){if(a?a.index(n)>-1:b.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}}return this.pushStack(o.length>1?b.unique(o):o)},index:function(e){return e?"string"==typeof e?b.inArray(this[0],b(e)):b.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?b(e,t):b.makeArray(e&&e.nodeType?[e]:e),r=b.merge(this.get(),n);return this.pushStack(b.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),b.fn.andSelf=b.fn.addBack;function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}b.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(e,t,n){return b.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(e,t,n){return b.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return b.dir(e,"previousSibling",n)},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.merge([],e.childNodes)}},function(e,t){b.fn[e]=function(n,r){var i=b.map(this,t,n);return at.test(e)||(r=n),r&&"string"==typeof r&&(i=b.filter(r,i)),i=this.length>1&&!ct[e]?b.unique(i):i,this.length>1&&st.test(e)&&(i=i.reverse()),this.pushStack(i)}}),b.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?b.find.matchesSelector(t[0],e)?[t[0]]:[]:b.find.matches(e,t)},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!b(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(t=t||0,b.isFunction(t))return b.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return b.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=b.grep(e,function(e){return 1===e.nodeType});if(ut.test(t))return b.filter(t,r,!n);t=b.filter(t,r)}return b.grep(e,function(e){return b.inArray(e,t)>=0===n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Nt=/^(?:checkbox|radio)$/i,Ct=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:b.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(o),Dt=jt.appendChild(o.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,b.fn.extend({text:function(e){return b.access(this,function(e){return e===t?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e))return this.each(function(t){b(this).wrapAll(e.call(this,t))});if(this[0]){var t=b(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return b.isFunction(e)?this.each(function(t){b(this).wrapInner(e.call(this,t))}):this.each(function(){var t=b(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=b.isFunction(e);return this.each(function(n){b(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){b.nodeName(this,"body")||b(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=0;for(;null!=(n=this[r]);r++)(!e||b.filter(e,[n]).length>0)&&(t||1!==n.nodeType||b.cleanData(Ot(n)),n.parentNode&&(t&&b.contains(n.ownerDocument,n)&&Mt(Ot(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&b.cleanData(Ot(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&b.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return b.clone(this,e,t)})},html:function(e){return b.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!b.support.htmlSerialize&&mt.test(e)||!b.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(b.cleanData(Ot(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=b.isFunction(e);return t||"string"==typeof e||(e=b(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;n&&(b(this).remove(),n.insertBefore(e,t))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=f.apply([],e);var i,o,a,s,u,l,c=0,p=this.length,d=this,h=p-1,g=e[0],m=b.isFunction(g);if(m||!(1>=p||"string"!=typeof g||b.support.checkClone)&&Ct.test(g))return this.each(function(i){var o=d.eq(i);m&&(e[0]=g.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(p&&(l=b.buildFragment(e,this[0].ownerDocument,!1,this),i=l.firstChild,1===l.childNodes.length&&(l=i),i)){for(n=n&&b.nodeName(i,"tr"),s=b.map(Ot(l,"script"),Ht),a=s.length;p>c;c++)o=l,c!==h&&(o=b.clone(o,!0,!0),a&&b.merge(s,Ot(o,"script"))),r.call(n&&b.nodeName(this[c],"table")?Lt(this[c],"tbody"):this[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,b.map(s,qt),c=0;a>c;c++)o=s[c],kt.test(o.type||"")&&!b._data(o,"globalEval")&&b.contains(u,o)&&(o.src?b.ajax({url:o.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):b.globalEval((o.text||o.textContent||o.innerHTML||"").replace(St,"")));l=i=null}return this}});function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function Ht(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Mt(e,t){var n,r=0;for(;null!=(n=e[r]);r++)b._data(n,"globalEval",!t||b._data(t[r],"globalEval"))}function _t(e,t){if(1===t.nodeType&&b.hasData(e)){var n,r,i,o=b._data(e),a=b._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)b.event.add(t,n,s[n][r])}a.data&&(a.data=b.extend({},a.data))}}function Ft(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!b.support.noCloneEvent&&t[b.expando]){i=b._data(t);for(r in i.events)b.removeEvent(t,r,i.handle);t.removeAttribute(b.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),b.support.html5Clone&&e.innerHTML&&!b.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Nt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}b.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){b.fn[e]=function(e){var n,r=0,i=[],o=b(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),b(o[r])[t](n),d.apply(i,n.get());return this.pushStack(i)}});function Ot(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||b.nodeName(o,n)?s.push(o):b.merge(s,Ot(o,n));return n===t||n&&b.nodeName(e,n)?b.merge([e],s):s}function Bt(e){Nt.test(e.type)&&(e.defaultChecked=e.checked)}b.extend({clone:function(e,t,n){var r,i,o,a,s,u=b.contains(e.ownerDocument,e);if(b.support.html5Clone||b.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(b.support.noCloneEvent&&b.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||b.isXMLDoc(e)))for(r=Ot(o),s=Ot(e),a=0;null!=(i=s[a]);++a)r[a]&&Ft(i,r[a]);if(t)if(n)for(s=s||Ot(e),r=r||Ot(o),a=0;null!=(i=s[a]);a++)_t(i,r[a]);else _t(e,o);return r=Ot(o,"script"),r.length>0&&Mt(r,!u&&Ot(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,u,l,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===b.type(o))b.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),u=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[u]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!b.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!b.support.tbody){o="table"!==u||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)b.nodeName(l=o.childNodes[i],"tbody")&&!l.childNodes.length&&o.removeChild(l) +}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function un(e){var t=o,n=Gt[e];return n||(n=ln(e,t),"none"!==n&&n||(Pt=(Pt||b("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=ln(e,t),Pt.detach()),Gt[e]=n),n}function ln(e,t){var n=b(t.createElement(e)).appendTo(t.body),r=b.css(n[0],"display");return n.remove(),r}b.each(["height","width"],function(e,n){b.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(b.css(e,"display"))?b.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,i),i):0)}}}),b.support.opacity||(b.cssHooks.opacity={get:function(e,t){return It.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=b.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===b.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),b(function(){b.support.reliableMarginRight||(b.cssHooks.marginRight={get:function(e,n){return n?b.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!b.support.pixelPosition&&b.fn.position&&b.each(["top","left"],function(e,n){b.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?b(e).position()[n]+"px":r):t}}})}),b.expr&&b.expr.filters&&(b.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!b.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||b.css(e,"display"))},b.expr.filters.visible=function(e){return!b.expr.filters.hidden(e)}),b.each({margin:"",padding:"",border:"Width"},function(e,t){b.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(b.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;b.fn.extend({serialize:function(){return b.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=b.prop(this,"elements");return e?b.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!b(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Nt.test(e))}).map(function(e,t){var n=b(this).val();return null==n?null:b.isArray(n)?b.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),b.param=function(e,n){var r,i=[],o=function(e,t){t=b.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=b.ajaxSettings&&b.ajaxSettings.traditional),b.isArray(e)||e.jquery&&!b.isPlainObject(e))b.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(b.isArray(t))b.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==b.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}b.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){b.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),b.fn.hover=function(e,t){return this.mouseenter(e).mouseleave(t||e)};var mn,yn,vn=b.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Nn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Cn=/^(?:GET|HEAD)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=b.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=a.href}catch(Ln){yn=o.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(b.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(u){var l;return o[u]=!0,b.each(e[u]||[],function(e,u){var c=u(n,r,i);return"string"!=typeof c||a||o[c]?a?!(l=c):t:(n.dataTypes.unshift(c),s(c),!1)}),l}return s(n.dataTypes[0])||!o["*"]&&s("*")}function Mn(e,n){var r,i,o=b.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&b.extend(!0,e,r),e}b.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,u=e.indexOf(" ");return u>=0&&(i=e.slice(u,e.length),e=e.slice(0,u)),b.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&b.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?b("<div>").append(b.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},b.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){b.fn[t]=function(e){return this.on(t,e)}}),b.each(["get","post"],function(e,n){b[n]=function(e,r,i,o){return b.isFunction(r)&&(o=o||i,i=r,r=t),b.ajax({url:e,type:n,dataType:o,data:r,success:i})}}),b.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Nn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Mn(Mn(e,b.ajaxSettings),t):Mn(b.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,u,l,c,p=b.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?b(f):b.event,h=b.Deferred(),g=b.Callbacks("once memory"),m=p.statusCode||{},y={},v={},x=0,T="canceled",N={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return x||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>x)for(t in e)m[t]=[m[t],e[t]];else N.always(e[N.status]);return this},abort:function(e){var t=e||T;return l&&l.abort(t),k(0,t),this}};if(h.promise(N).complete=g.add,N.success=N.done,N.error=N.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=b.trim(p.dataType||"*").toLowerCase().match(w)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?80:443))==(mn[3]||("http:"===mn[1]?80:443)))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=b.param(p.data,p.traditional)),qn(An,p,n,N),2===x)return N;u=p.global,u&&0===b.active++&&b.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Cn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(b.lastModified[o]&&N.setRequestHeader("If-Modified-Since",b.lastModified[o]),b.etag[o]&&N.setRequestHeader("If-None-Match",b.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&N.setRequestHeader("Content-Type",p.contentType),N.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)N.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,N,p)===!1||2===x))return N.abort();T="abort";for(i in{success:1,error:1,complete:1})N[i](p[i]);if(l=qn(jn,p,n,N)){N.readyState=1,u&&d.trigger("ajaxSend",[N,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){N.abort("timeout")},p.timeout));try{x=1,l.send(y,k)}catch(C){if(!(2>x))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,C=n;2!==x&&(x=2,s&&clearTimeout(s),l=t,a=i||"",N.readyState=e>0?4:0,r&&(w=_n(p,N,r)),e>=200&&300>e||304===e?(p.ifModified&&(T=N.getResponseHeader("Last-Modified"),T&&(b.lastModified[o]=T),T=N.getResponseHeader("etag"),T&&(b.etag[o]=T)),204===e?(c=!0,C="nocontent"):304===e?(c=!0,C="notmodified"):(c=Fn(p,w),C=c.state,y=c.data,v=c.error,c=!v)):(v=C,(e||!C)&&(C="error",0>e&&(e=0))),N.status=e,N.statusText=(n||C)+"",c?h.resolveWith(f,[y,C,N]):h.rejectWith(f,[N,C,v]),N.statusCode(m),m=t,u&&d.trigger(c?"ajaxSuccess":"ajaxError",[N,p,c?y:v]),g.fireWith(f,[N,C]),u&&(d.trigger("ajaxComplete",[N,p]),--b.active||b.event.trigger("ajaxStop")))}return N},getScript:function(e,n){return b.get(e,t,n,"script")},getJSON:function(e,t,n){return b.get(e,t,n,"json")}});function _n(e,n,r){var i,o,a,s,u=e.contents,l=e.dataTypes,c=e.responseFields;for(s in c)s in r&&(n[c[s]]=r[s]);while("*"===l[0])l.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in u)if(u[s]&&u[s].test(o)){l.unshift(s);break}if(l[0]in r)a=l[0];else{for(s in r){if(!l[0]||e.converters[s+" "+l[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==l[0]&&l.unshift(a),r[a]):t}function Fn(e,t){var n,r,i,o,a={},s=0,u=e.dataTypes.slice(),l=u[0];if(e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u[1])for(i in e.converters)a[i.toLowerCase()]=e.converters[i];for(;r=u[++s];)if("*"!==r){if("*"!==l&&l!==r){if(i=a[l+" "+r]||a["* "+r],!i)for(n in a)if(o=n.split(" "),o[1]===r&&(i=a[l+" "+o[0]]||a["* "+o[0]])){i===!0?i=a[n]:a[n]!==!0&&(r=o[0],u.splice(s--,0,r));break}if(i!==!0)if(i&&e["throws"])t=i(t);else try{t=i(t)}catch(c){return{state:"parsererror",error:i?c:"No conversion from "+l+" to "+r}}}l=r}return{state:"success",data:t}}b.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return b.globalEval(e),e}}}),b.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),b.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=o.head||b("head")[0]||o.documentElement;return{send:function(t,i){n=o.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var On=[],Bn=/(=)\?(?=&|$)|\?\?/;b.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=On.pop()||b.expando+"_"+vn++;return this[e]=!0,e}}),b.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,u=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return u||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=b.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,u?n[u]=n[u].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||b.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,On.push(o)),s&&b.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}b.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=b.ajaxSettings.xhr(),b.support.cors=!!Rn&&"withCredentials"in Rn,Rn=b.support.ajax=!!Rn,Rn&&b.ajaxTransport(function(n){if(!n.crossDomain||b.support.cors){var r;return{send:function(i,o){var a,s,u=n.xhr();if(n.username?u.open(n.type,n.url,n.async,n.username,n.password):u.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)u[s]=n.xhrFields[s];n.mimeType&&u.overrideMimeType&&u.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)u.setRequestHeader(s,i[s])}catch(l){}u.send(n.hasContent&&n.data||null),r=function(e,i){var s,l,c,p;try{if(r&&(i||4===u.readyState))if(r=t,a&&(u.onreadystatechange=b.noop,$n&&delete Pn[a]),i)4!==u.readyState&&u.abort();else{p={},s=u.status,l=u.getAllResponseHeaders(),"string"==typeof u.responseText&&(p.text=u.responseText);try{c=u.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,l)},n.async?4===u.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},b(e).unload($n)),Pn[a]=r),u.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+x+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n,r,i=this.createTween(e,t),o=Yn.exec(t),a=i.cur(),s=+a||0,u=1,l=20;if(o){if(n=+o[2],r=o[3]||(b.cssNumber[e]?"":"px"),"px"!==r&&s){s=b.css(i.elem,e,!0)||n||1;do u=u||".5",s/=u,b.style(i.elem,e,s+r);while(u!==(u=i.cur()/a)&&1!==u&&--l)}i.unit=r,i.start=s,i.end=o[1]?s+(o[1]+1)*n:n}return i}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=b.now()}function Zn(e,t){b.each(t,function(t,n){var r=(Qn[t]||[]).concat(Qn["*"]),i=0,o=r.length;for(;o>i;i++)if(r[i].call(e,t,n))return})}function er(e,t,n){var r,i,o=0,a=Gn.length,s=b.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;for(;u>a;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),1>o&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:b.extend({},t),opts:b.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=b.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?s.resolveWith(e,[l,t]):s.rejectWith(e,[l,t]),this}}),c=l.props;for(tr(c,l.opts.specialEasing);a>o;o++)if(r=Gn[o].call(l,e,c,l.opts))return r;return Zn(l,c),b.isFunction(l.opts.start)&&l.opts.start.call(e,l),b.fx.timer(b.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function tr(e,t){var n,r,i,o,a;for(i in e)if(r=b.camelCase(i),o=t[r],n=e[i],b.isArray(n)&&(o=n[1],n=e[i]=n[0]),i!==r&&(e[r]=n,delete e[i]),a=b.cssHooks[r],a&&"expand"in a){n=a.expand(n),delete e[r];for(i in n)i in e||(e[i]=n[i],t[i]=o)}else t[r]=o}b.Animation=b.extend(er,{tweener:function(e,t){b.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,u,l,c,p,f=this,d=e.style,h={},g=[],m=e.nodeType&&nn(e);n.queue||(c=b._queueHooks(e,"fx"),null==c.unqueued&&(c.unqueued=0,p=c.empty.fire,c.empty.fire=function(){c.unqueued||p()}),c.unqueued++,f.always(function(){f.always(function(){c.unqueued--,b.queue(e,"fx").length||c.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[d.overflow,d.overflowX,d.overflowY],"inline"===b.css(e,"display")&&"none"===b.css(e,"float")&&(b.support.inlineBlockNeedsLayout&&"inline"!==un(e.nodeName)?d.zoom=1:d.display="inline-block")),n.overflow&&(d.overflow="hidden",b.support.shrinkWrapBlocks||f.always(function(){d.overflow=n.overflow[0],d.overflowX=n.overflow[1],d.overflowY=n.overflow[2]}));for(i in t)if(a=t[i],Vn.exec(a)){if(delete t[i],u=u||"toggle"===a,a===(m?"hide":"show"))continue;g.push(i)}if(o=g.length){s=b._data(e,"fxshow")||b._data(e,"fxshow",{}),"hidden"in s&&(m=s.hidden),u&&(s.hidden=!m),m?b(e).show():f.done(function(){b(e).hide()}),f.done(function(){var t;b._removeData(e,"fxshow");for(t in h)b.style(e,t,h[t])});for(i=0;o>i;i++)r=g[i],l=f.createTween(r,m?s[r]:0),h[r]=s[r]||b.style(e,r),r in s||(s[r]=l.start,m&&(l.end=l.start,l.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}b.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(b.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?b.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=b.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){b.fx.step[e.prop]?b.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[b.cssProps[e.prop]]||b.cssHooks[e.prop])?b.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},b.each(["toggle","show","hide"],function(e,t){var n=b.fn[t];b.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),b.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=b.isEmptyObject(e),o=b.speed(t,n,r),a=function(){var t=er(this,b.extend({},e),o);a.finish=function(){t.stop(!0)},(i||b._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=b.timers,a=b._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&b.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=b._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=b.timers,a=r?r.length:0;for(n.finish=!0,b.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}b.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){b.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),b.speed=function(e,t,n){var r=e&&"object"==typeof e?b.extend({},e):{complete:n||!n&&t||b.isFunction(e)&&e,duration:e,easing:n&&t||t&&!b.isFunction(t)&&t};return r.duration=b.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in b.fx.speeds?b.fx.speeds[r.duration]:b.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){b.isFunction(r.old)&&r.old.call(this),r.queue&&b.dequeue(this,r.queue)},r},b.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},b.timers=[],b.fx=rr.prototype.init,b.fx.tick=function(){var e,n=b.timers,r=0;for(Xn=b.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||b.fx.stop(),Xn=t},b.fx.timer=function(e){e()&&b.timers.push(e)&&b.fx.start()},b.fx.interval=13,b.fx.start=function(){Un||(Un=setInterval(b.fx.tick,b.fx.interval))},b.fx.stop=function(){clearInterval(Un),Un=null},b.fx.speeds={slow:600,fast:200,_default:400},b.fx.step={},b.expr&&b.expr.filters&&(b.expr.filters.animated=function(e){return b.grep(b.timers,function(t){return e===t.elem}).length}),b.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){b.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,b.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},b.offset={setOffset:function(e,t,n){var r=b.css(e,"position");"static"===r&&(e.style.position="relative");var i=b(e),o=i.offset(),a=b.css(e,"top"),s=b.css(e,"left"),u=("absolute"===r||"fixed"===r)&&b.inArray("auto",[a,s])>-1,l={},c={},p,f;u?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),b.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(l.top=t.top-o.top+p),null!=t.left&&(l.left=t.left-o.left+f),"using"in t?t.using.call(e,l):i.css(l)}},b.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===b.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),b.nodeName(e[0],"html")||(n=e.offset()),n.top+=b.css(e[0],"borderTopWidth",!0),n.left+=b.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-b.css(r,"marginTop",!0),left:t.left-n.left-b.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||o.documentElement;while(e&&!b.nodeName(e,"html")&&"static"===b.css(e,"position"))e=e.offsetParent;return e||o.documentElement})}}),b.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);b.fn[e]=function(i){return b.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?b(a).scrollLeft():o,r?o:b(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return b.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}b.each({Height:"height",Width:"width"},function(e,n){b.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){b.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return b.access(this,function(n,r,i){var o;return b.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?b.css(n,r,s):b.style(n,r,i,s)},n,a?i:t,a,null)}})}),e.jQuery=e.$=b,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return b})})(window); diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/jquery.min.map b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/jquery.min.map @@ -0,0 +1 @@ +{"version":3,"file":"jquery.min.js","sources":["jquery.js"],"names":["window","undefined","readyList","rootjQuery","core_strundefined","document","location","_jQuery","jQuery","_$","$","class2type","core_deletedIds","core_version","core_concat","concat","core_push","push","core_slice","slice","core_indexOf","indexOf","core_toString","toString","core_hasOwn","hasOwnProperty","core_trim","trim","selector","context","fn","init","core_pnum","source","core_rnotwhite","rtrim","rquickExpr","rsingleTag","rvalidchars","rvalidbraces","rvalidescape","rvalidtokens","rmsPrefix","rdashAlpha","fcamelCase","all","letter","toUpperCase","completed","event","addEventListener","type","readyState","detach","ready","removeEventListener","detachEvent","prototype","jquery","constructor","match","elem","this","charAt","length","exec","find","merge","parseHTML","nodeType","ownerDocument","test","isPlainObject","isFunction","attr","getElementById","parentNode","id","makeArray","size","toArray","call","get","num","pushStack","elems","ret","prevObject","each","callback","args","promise","done","apply","arguments","first","eq","last","i","len","j","map","end","sort","splice","extend","src","copyIsArray","copy","name","options","clone","target","deep","isArray","noConflict","isReady","readyWait","holdReady","hold","wait","body","setTimeout","resolveWith","trigger","off","obj","Array","isWindow","isNumeric","isNaN","parseFloat","isFinite","String","e","key","isEmptyObject","error","msg","Error","data","keepScripts","parsed","scripts","createElement","buildFragment","remove","childNodes","parseJSON","JSON","parse","replace","Function","parseXML","xml","tmp","DOMParser","parseFromString","ActiveXObject","async","loadXML","documentElement","getElementsByTagName","noop","globalEval","execScript","camelCase","string","nodeName","toLowerCase","value","isArraylike","text","arr","results","Object","inArray","Math","max","second","l","grep","inv","retVal","arg","guid","proxy","access","chainable","emptyGet","raw","bulk","now","Date","getTime","Deferred","attachEvent","top","frameElement","doScroll","doScrollCheck","split","optionsCache","createOptions","object","_","flag","Callbacks","firing","memory","fired","firingLength","firingIndex","firingStart","list","stack","once","fire","stopOnFalse","shift","self","disable","add","start","unique","has","index","empty","disabled","lock","locked","fireWith","func","tuples","state","always","deferred","fail","then","fns","newDefer","tuple","action","returned","resolve","reject","progress","notify","pipe","stateString","when","subordinate","resolveValues","remaining","updateFunc","contexts","values","progressValues","notifyWith","progressContexts","resolveContexts","support","a","input","select","fragment","opt","eventName","isSupported","div","setAttribute","innerHTML","appendChild","style","cssText","getSetAttribute","className","leadingWhitespace","firstChild","tbody","htmlSerialize","getAttribute","hrefNormalized","opacity","cssFloat","checkOn","optSelected","selected","enctype","html5Clone","cloneNode","outerHTML","boxModel","compatMode","deleteExpando","noCloneEvent","inlineBlockNeedsLayout","shrinkWrapBlocks","reliableMarginRight","boxSizingReliable","pixelPosition","checked","noCloneChecked","optDisabled","radioValue","createDocumentFragment","appendChecked","checkClone","lastChild","click","submit","change","focusin","attributes","expando","backgroundClip","clearCloneStyle","container","marginDiv","tds","divReset","offsetHeight","display","reliableHiddenOffsets","boxSizing","offsetWidth","doesNotIncludeMarginInBodyOffset","offsetTop","getComputedStyle","width","marginRight","zoom","removeChild","rbrace","rmultiDash","internalData","pvt","acceptData","thisCache","internalKey","getByName","isNode","cache","pop","toJSON","internalRemoveData","isEmptyDataObject","cleanData","random","noData","embed","applet","hasData","removeData","_data","_removeData","attrs","dataAttr","queue","dequeue","startLength","hooks","_queueHooks","next","cur","unshift","stop","setter","delay","time","fx","speeds","timeout","clearTimeout","clearQueue","count","defer","elements","nodeHook","boolHook","rclass","rreturn","rfocusable","rclickable","rboolean","ruseDefault","getSetInput","removeAttr","prop","removeProp","propFix","addClass","classes","clazz","proceed","removeClass","toggleClass","stateVal","isBool","classNames","hasClass","val","valHooks","set","option","specified","selectedIndex","one","notxml","nType","isXMLDoc","attrHooks","propName","attrNames","removeAttribute","tabindex","readonly","for","class","maxlength","cellspacing","cellpadding","rowspan","colspan","usemap","frameborder","contenteditable","propHooks","tabIndex","attributeNode","getAttributeNode","parseInt","href","detail","defaultValue","button","setAttributeNode","createAttribute","parent","rformElems","rkeyEvent","rmouseEvent","rfocusMorph","rtypenamespace","returnTrue","returnFalse","global","types","handler","events","t","handleObjIn","special","eventHandle","handleObj","handlers","namespaces","origType","elemData","handle","triggered","dispatch","delegateType","bindType","needsContext","expr","namespace","join","delegateCount","setup","mappedTypes","origCount","RegExp","teardown","removeEvent","onlyHandlers","ontype","bubbleType","eventPath","Event","isTrigger","namespace_re","result","noBubble","defaultView","parentWindow","isPropagationStopped","preventDefault","isDefaultPrevented","_default","fix","matched","handlerQueue","delegateTarget","preDispatch","currentTarget","isImmediatePropagationStopped","stopPropagation","postDispatch","sel","matches","originalEvent","fixHook","fixHooks","mouseHooks","keyHooks","props","srcElement","metaKey","filter","original","which","charCode","keyCode","eventDoc","doc","fromElement","pageX","clientX","scrollLeft","clientLeft","pageY","clientY","scrollTop","clientTop","relatedTarget","toElement","load","focus","activeElement","blur","beforeunload","returnValue","simulate","bubble","isSimulated","defaultPrevented","getPreventDefault","timeStamp","cancelBubble","stopImmediatePropagation","mouseenter","mouseleave","orig","related","contains","submitBubbles","form","_submit_bubble","changeBubbles","propertyName","_just_changed","focusinBubbles","attaches","on","origFn","bind","unbind","delegate","undelegate","triggerHandler","cachedruns","Expr","getText","isXML","compile","hasDuplicate","outermostContext","setDocument","docElem","documentIsXML","rbuggyQSA","rbuggyMatches","sortOrder","preferredDoc","dirruns","classCache","createCache","tokenCache","compilerCache","strundefined","MAX_NEGATIVE","whitespace","characterEncoding","identifier","operators","pseudos","rcomma","rcombinators","rpseudo","ridentifier","matchExpr","ID","CLASS","NAME","TAG","ATTR","PSEUDO","CHILD","rsibling","rnative","rinputs","rheader","rescape","rattributeQuotes","runescape","funescape","escaped","high","fromCharCode","isNative","keys","cacheLength","markFunction","assert","Sizzle","seed","m","groups","old","nid","newContext","newSelector","getByClassName","getElementsByClassName","qsa","tokenize","toSelector","querySelectorAll","qsaError","node","tagNameNoComments","createComment","insertBefore","pass","getElementsByName","getIdNotName","attrHandle","attrId","tag","matchesSelector","mozMatchesSelector","webkitMatchesSelector","oMatchesSelector","msMatchesSelector","disconnectedMatch","compareDocumentPosition","b","adown","bup","compare","aup","ap","bp","siblingCheck","detectDuplicates","uniqueSort","duplicates","diff","sourceIndex","nextSibling","createInputPseudo","createButtonPseudo","createPositionalPseudo","argument","matchIndexes","textContent","nodeValue","selectors","createPseudo","relative",">","dir"," ","+","~","preFilter","excess","unquoted","pattern","operator","check","what","simple","forward","ofType","outerCache","nodeIndex","useCache","pseudo","setFilters","idx","not","matcher","unmatched","innerText","lang","elemLang","hash","root","hasFocus","enabled","header","even","odd","lt","gt","radio","checkbox","file","password","image","reset","parseOnly","tokens","soFar","preFilters","cached","addCombinator","combinator","base","checkNonElements","doneName","dirkey","elementMatcher","matchers","condense","newUnmatched","mapped","setMatcher","postFilter","postFinder","postSelector","temp","preMap","postMap","preexisting","multipleContexts","matcherIn","matcherOut","matcherFromTokens","checkContext","leadingRelative","implicitRelative","matchContext","matchAnyContext","matcherFromGroupMatchers","elementMatchers","setMatchers","matcherCachedRuns","bySet","byElement","superMatcher","expandContext","setMatched","matchedCount","outermost","contextBackup","dirrunsUnique","group","token","filters","runtil","rparentsprev","isSimple","rneedsContext","guaranteedUnique","children","contents","prev","targets","winnow","is","closest","pos","prevAll","addBack","andSelf","sibling","parents","parentsUntil","until","nextAll","nextUntil","prevUntil","siblings","contentDocument","contentWindow","reverse","n","r","qualifier","keep","filtered","createSafeFragment","nodeNames","safeFrag","rinlinejQuery","rnoshimcache","rleadingWhitespace","rxhtmlTag","rtagName","rtbody","rhtml","rnoInnerhtml","manipulation_rcheckableType","rchecked","rscriptType","rscriptTypeMasked","rcleanScript","wrapMap","legend","area","param","thead","tr","col","td","safeFragment","fragmentDiv","optgroup","tfoot","colgroup","caption","th","append","createTextNode","wrapAll","html","wrap","wrapInner","unwrap","replaceWith","domManip","prepend","before","after","keepData","getAll","setGlobalEval","dataAndEvents","deepDataAndEvents","isFunc","table","hasScripts","iNoClone","disableScript","findOrAppend","restoreScript","ajax","url","dataType","throws","refElements","cloneCopyEvent","dest","oldData","curData","fixCloneNodeIssues","defaultChecked","defaultSelected","appendTo","prependTo","insertAfter","replaceAll","insert","found","fixDefaultChecked","destElements","srcElements","inPage","selection","safe","nodes","iframe","getStyles","curCSS","ralpha","ropacity","rposition","rdisplayswap","rmargin","rnumsplit","rnumnonpx","rrelNum","elemdisplay","BODY","cssShow","position","visibility","cssNormalTransform","letterSpacing","fontWeight","cssExpand","cssPrefixes","vendorPropName","capName","origName","isHidden","el","css","showHide","show","hidden","css_defaultDisplay","styles","hide","toggle","bool","cssHooks","computed","cssNumber","columnCount","fillOpacity","lineHeight","orphans","widows","zIndex","cssProps","float","extra","swap","_computed","minWidth","maxWidth","getPropertyValue","currentStyle","left","rs","rsLeft","runtimeStyle","pixelLeft","setPositiveNumber","subtract","augmentWidthOrHeight","isBorderBox","getWidthOrHeight","valueIsBorderBox","actualDisplay","write","close","$1","visible","margin","padding","border","prefix","suffix","expand","expanded","parts","r20","rbracket","rCRLF","rsubmitterTypes","rsubmittable","serialize","serializeArray","traditional","s","encodeURIComponent","ajaxSettings","buildParams","v","hover","fnOver","fnOut","ajaxLocParts","ajaxLocation","ajax_nonce","ajax_rquery","rhash","rts","rheaders","rlocalProtocol","rnoContent","rprotocol","rurl","_load","prefilters","transports","allTypes","addToPrefiltersOrTransports","structure","dataTypeExpression","dataTypes","inspectPrefiltersOrTransports","originalOptions","jqXHR","inspected","seekingTransport","inspect","prefilterOrFactory","dataTypeOrTransport","ajaxExtend","flatOptions","params","response","responseText","complete","status","method","success","active","lastModified","etag","isLocal","processData","contentType","accepts","*","json","responseFields","converters","* text","text html","text json","text xml","ajaxSetup","settings","ajaxPrefilter","ajaxTransport","cacheURL","responseHeadersString","timeoutTimer","fireGlobals","transport","responseHeaders","callbackContext","globalEventContext","completeDeferred","statusCode","requestHeaders","requestHeadersNames","strAbort","getResponseHeader","getAllResponseHeaders","setRequestHeader","lname","overrideMimeType","mimeType","code","abort","statusText","finalText","crossDomain","hasContent","ifModified","headers","beforeSend","send","nativeStatusText","responses","isSuccess","modified","ajaxHandleResponses","ajaxConvert","rejectWith","getScript","getJSON","firstDataType","ct","finalDataType","conv2","current","conv","dataFilter","script","text script","head","scriptCharset","charset","onload","onreadystatechange","isAbort","oldCallbacks","rjsonp","jsonp","jsonpCallback","originalSettings","callbackName","overwritten","responseContainer","jsonProp","xhrCallbacks","xhrSupported","xhrId","xhrOnUnloadAbort","createStandardXHR","XMLHttpRequest","createActiveXHR","xhr","cors","username","open","xhrFields","err","firefoxAccessException","unload","fxNow","timerId","rfxtypes","rfxnum","rrun","animationPrefilters","defaultPrefilter","tweeners","unit","tween","createTween","scale","maxIterations","createFxNow","createTweens","animation","collection","Animation","properties","stopped","tick","currentTime","startTime","duration","percent","tweens","run","opts","specialEasing","originalProperties","Tween","easing","gotoEnd","propFilter","timer","anim","tweener","prefilter","dataShow","oldfire","handled","unqueued","overflow","overflowX","overflowY","eased","step","cssFn","speed","animate","genFx","fadeTo","to","optall","doAnimation","finish","stopQueue","timers","includeWidth","height","slideDown","slideUp","slideToggle","fadeIn","fadeOut","fadeToggle","linear","p","swing","cos","PI","interval","setInterval","clearInterval","slow","fast","animated","offset","setOffset","win","box","getBoundingClientRect","getWindow","pageYOffset","pageXOffset","curElem","curOffset","curCSSTop","curCSSLeft","calculatePosition","curPosition","curTop","curLeft","using","offsetParent","parentOffset","scrollTo","Height","Width","content","defaultExtra","funcName","define","amd"],"mappings":"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"} +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/js/bootstrap.js b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/js/bootstrap.js @@ -0,0 +1,1951 @@ +/*! + * Bootstrap v3.1.1 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript requires jQuery') } + +/* ======================================================================== + * Bootstrap: transition.js v3.1.1 + * http://getbootstrap.com/javascript/#transitions + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ + + function transitionEnd() { + var el = document.createElement('bootstrap') + + var transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd', + 'MozTransition' : 'transitionend', + 'OTransition' : 'oTransitionEnd otransitionend', + 'transition' : 'transitionend' + } + + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } + } + + return false // explicit for ie8 ( ._.) + } + + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function (duration) { + var called = false, $el = this + $(this).one($.support.transition.end, function () { called = true }) + var callback = function () { if (!called) $($el).trigger($.support.transition.end) } + setTimeout(callback, duration) + return this + } + + $(function () { + $.support.transition = transitionEnd() + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: alert.js v3.1.1 + * http://getbootstrap.com/javascript/#alerts + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // ALERT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.hasClass('alert') ? $this : $this.parent() + } + + $parent.trigger(e = $.Event('close.bs.alert')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent.trigger('closed.bs.alert').remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent + .one($.support.transition.end, removeElement) + .emulateTransitionEnd(150) : + removeElement() + } + + + // ALERT PLUGIN DEFINITION + // ======================= + + var old = $.fn.alert + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.alert') + + if (!data) $this.data('bs.alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + // ALERT NO CONFLICT + // ================= + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + // ALERT DATA-API + // ============== + + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: button.js v3.1.1 + * http://getbootstrap.com/javascript/#buttons + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + this.isLoading = false + } + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (!data.resetText) $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout($.proxy(function () { + if (state == 'loadingText') { + this.isLoading = true + $el.addClass(d).attr(d, d) + } else if (this.isLoading) { + this.isLoading = false + $el.removeClass(d).removeAttr(d) + } + }, this), 0) + } + + Button.prototype.toggle = function () { + var changed = true + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + if ($input.prop('type') == 'radio') { + if ($input.prop('checked') && this.$element.hasClass('active')) changed = false + else $parent.find('.active').removeClass('active') + } + if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') + } + + if (changed) this.$element.toggleClass('active') + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + var old = $.fn.button + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + e.preventDefault() + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: carousel.js v3.1.1 + * http://getbootstrap.com/javascript/#carousel + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = + this.sliding = + this.interval = + this.$active = + this.$items = null + + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.DEFAULTS = { + interval: 5000, + pause: 'hover', + wrap: true + } + + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) + + this.interval && clearInterval(this.interval) + + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + + return this + } + + Carousel.prototype.getActiveIndex = function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + + return this.$items.index(this.$active) + } + + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getActiveIndex() + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) + if (activeIndex == pos) return this.pause().cycle() + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + Carousel.prototype.pause = function (e) { + e || (this.paused = true) + + if (this.$element.find('.next, .prev').length && $.support.transition) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + + this.interval = clearInterval(this.interval) + + return this + } + + Carousel.prototype.next = function () { + if (this.sliding) return + return this.slide('next') + } + + Carousel.prototype.prev = function () { + if (this.sliding) return + return this.slide('prev') + } + + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || $active[type]() + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var fallback = type == 'next' ? 'first' : 'last' + var that = this + + if (!$next.length) { + if (!this.options.wrap) return + $next = this.$element.find('.item')[fallback]() + } + + if ($next.hasClass('active')) return this.sliding = false + + var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + + this.sliding = true + + isCycling && this.pause() + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid.bs.carousel', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + + if ($.support.transition && this.$element.hasClass('slide')) { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0) + }) + .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000) + } else { + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid.bs.carousel') + } + + isCycling && this.cycle() + + return this + } + + + // CAROUSEL PLUGIN DEFINITION + // ========================== + + var old = $.fn.carousel + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide + + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + $.fn.carousel.Constructor = Carousel + + + // CAROUSEL NO CONFLICT + // ==================== + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + + // CAROUSEL DATA-API + // ================= + + $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) options.interval = false + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('bs.carousel').to(slideIndex) + } + + e.preventDefault() + }) + + $(window).on('load', function () { + $('[data-ride="carousel"]').each(function () { + var $carousel = $(this) + $carousel.carousel($carousel.data()) + }) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: collapse.js v3.1.1 + * http://getbootstrap.com/javascript/#collapse + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.transitioning = null + + if (this.options.parent) this.$parent = $(this.options.parent) + if (this.options.toggle) this.toggle() + } + + Collapse.DEFAULTS = { + toggle: true + } + + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) return + + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var actives = this.$parent && this.$parent.find('> .panel > .in') + + if (actives && actives.length) { + var hasData = actives.data('bs.collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('bs.collapse', null) + } + + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + .addClass('collapsing') + [dimension](0) + + this.transitioning = 1 + + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('collapse in') + [dimension]('auto') + this.transitioning = 0 + this.$element.trigger('shown.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + var scrollSize = $.camelCase(['scroll', dimension].join('-')) + + this.$element + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + [dimension](this.$element[0][scrollSize]) + } + + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) return + + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var dimension = this.dimension() + + this.$element + [dimension](this.$element[dimension]()) + [0].offsetHeight + + this.$element + .addClass('collapsing') + .removeClass('collapse') + .removeClass('in') + + this.transitioning = 1 + + var complete = function () { + this.transitioning = 0 + this.$element + .trigger('hidden.bs.collapse') + .removeClass('collapsing') + .addClass('collapse') + } + + if (!$.support.transition) return complete.call(this) + + this.$element + [dimension](0) + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + } + + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + + // COLLAPSE PLUGIN DEFINITION + // ========================== + + var old = $.fn.collapse + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data && options.toggle && option == 'show') option = !option + if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.Constructor = Collapse + + + // COLLAPSE NO CONFLICT + // ==================== + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + // COLLAPSE DATA-API + // ================= + + $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + var target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + var $target = $(target) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $this.data() + var parent = $this.attr('data-parent') + var $parent = parent && $(parent) + + if (!data || !data.transitioning) { + if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') + $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + } + + $target.collapse(option) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: dropdown.js v3.1.1 + * http://getbootstrap.com/javascript/#dropdowns + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // DROPDOWN CLASS DEFINITION + // ========================= + + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle=dropdown]' + var Dropdown = function (element) { + $(element).on('click.bs.dropdown', this.toggle) + } + + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we use a backdrop because click events don't delegate + $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus) + } + + var relatedTarget = { relatedTarget: this } + $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget)) + + if (e.isDefaultPrevented()) return + + $parent + .toggleClass('open') + .trigger('shown.bs.dropdown', relatedTarget) + + $this.trigger('focus') + } + + return false + } + + Dropdown.prototype.keydown = function (e) { + if (!/(38|40|27)/.test(e.keyCode)) return + + var $this = $(this) + + e.preventDefault() + e.stopPropagation() + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + if (!isActive || (isActive && e.keyCode == 27)) { + if (e.which == 27) $parent.find(toggle).trigger('focus') + return $this.trigger('click') + } + + var desc = ' li:not(.divider):visible a' + var $items = $parent.find('[role=menu]' + desc + ', [role=listbox]' + desc) + + if (!$items.length) return + + var index = $items.index($items.filter(':focus')) + + if (e.keyCode == 38 && index > 0) index-- // up + if (e.keyCode == 40 && index < $items.length - 1) index++ // down + if (!~index) index = 0 + + $items.eq(index).trigger('focus') + } + + function clearMenus(e) { + $(backdrop).remove() + $(toggle).each(function () { + var $parent = getParent($(this)) + var relatedTarget = { relatedTarget: this } + if (!$parent.hasClass('open')) return + $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget)) + if (e.isDefaultPrevented()) return + $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget) + }) + } + + function getParent($this) { + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + var $parent = selector && $(selector) + + return $parent && $parent.length ? $parent : $this.parent() + } + + + // DROPDOWN PLUGIN DEFINITION + // ========================== + + var old = $.fn.dropdown + + $.fn.dropdown = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.dropdown') + + if (!data) $this.data('bs.dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + // DROPDOWN NO CONFLICT + // ==================== + + $.fn.dropdown.noConflict = function () { + $.fn.dropdown = old + return this + } + + + // APPLY TO STANDARD DROPDOWN ELEMENTS + // =================================== + + $(document) + .on('click.bs.dropdown.data-api', clearMenus) + .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) + .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle) + .on('keydown.bs.dropdown.data-api', toggle + ', [role=menu], [role=listbox]', Dropdown.prototype.keydown) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: modal.js v3.1.1 + * http://getbootstrap.com/javascript/#modals + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // MODAL CLASS DEFINITION + // ====================== + + var Modal = function (element, options) { + this.options = options + this.$element = $(element) + this.$backdrop = + this.isShown = null + + if (this.options.remote) { + this.$element + .find('.modal-content') + .load(this.options.remote, $.proxy(function () { + this.$element.trigger('loaded.bs.modal') + }, this)) + } + } + + Modal.DEFAULTS = { + backdrop: true, + keyboard: true, + show: true + } + + Modal.prototype.toggle = function (_relatedTarget) { + return this[!this.isShown ? 'show' : 'hide'](_relatedTarget) + } + + Modal.prototype.show = function (_relatedTarget) { + var that = this + var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) + + this.$element.trigger(e) + + if (this.isShown || e.isDefaultPrevented()) return + + this.isShown = true + + this.escape() + + this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) + + this.backdrop(function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + if (!that.$element.parent().length) { + that.$element.appendTo(document.body) // don't move modals dom position + } + + that.$element + .show() + .scrollTop(0) + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element + .addClass('in') + .attr('aria-hidden', false) + + that.enforceFocus() + + var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) + + transition ? + that.$element.find('.modal-dialog') // wait for modal to slide in + .one($.support.transition.end, function () { + that.$element.trigger('focus').trigger(e) + }) + .emulateTransitionEnd(300) : + that.$element.trigger('focus').trigger(e) + }) + } + + Modal.prototype.hide = function (e) { + if (e) e.preventDefault() + + e = $.Event('hide.bs.modal') + + this.$element.trigger(e) + + if (!this.isShown || e.isDefaultPrevented()) return + + this.isShown = false + + this.escape() + + $(document).off('focusin.bs.modal') + + this.$element + .removeClass('in') + .attr('aria-hidden', true) + .off('click.dismiss.bs.modal') + + $.support.transition && this.$element.hasClass('fade') ? + this.$element + .one($.support.transition.end, $.proxy(this.hideModal, this)) + .emulateTransitionEnd(300) : + this.hideModal() + } + + Modal.prototype.enforceFocus = function () { + $(document) + .off('focusin.bs.modal') // guard against infinite focus loop + .on('focusin.bs.modal', $.proxy(function (e) { + if (this.$element[0] !== e.target && !this.$element.has(e.target).length) { + this.$element.trigger('focus') + } + }, this)) + } + + Modal.prototype.escape = function () { + if (this.isShown && this.options.keyboard) { + this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) { + e.which == 27 && this.hide() + }, this)) + } else if (!this.isShown) { + this.$element.off('keyup.dismiss.bs.modal') + } + } + + Modal.prototype.hideModal = function () { + var that = this + this.$element.hide() + this.backdrop(function () { + that.removeBackdrop() + that.$element.trigger('hidden.bs.modal') + }) + } + + Modal.prototype.removeBackdrop = function () { + this.$backdrop && this.$backdrop.remove() + this.$backdrop = null + } + + Modal.prototype.backdrop = function (callback) { + var animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />') + .appendTo(document.body) + + this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) { + if (e.target !== e.currentTarget) return + this.options.backdrop == 'static' + ? this.$element[0].focus.call(this.$element[0]) + : this.hide.call(this) + }, this)) + + if (doAnimate) this.$backdrop[0].offsetWidth // force reflow + + this.$backdrop.addClass('in') + + if (!callback) return + + doAnimate ? + this.$backdrop + .one($.support.transition.end, callback) + .emulateTransitionEnd(150) : + callback() + + } else if (!this.isShown && this.$backdrop) { + this.$backdrop.removeClass('in') + + $.support.transition && this.$element.hasClass('fade') ? + this.$backdrop + .one($.support.transition.end, callback) + .emulateTransitionEnd(150) : + callback() + + } else if (callback) { + callback() + } + } + + + // MODAL PLUGIN DEFINITION + // ======================= + + var old = $.fn.modal + + $.fn.modal = function (option, _relatedTarget) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.modal') + var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) $this.data('bs.modal', (data = new Modal(this, options))) + if (typeof option == 'string') data[option](_relatedTarget) + else if (options.show) data.show(_relatedTarget) + }) + } + + $.fn.modal.Constructor = Modal + + + // MODAL NO CONFLICT + // ================= + + $.fn.modal.noConflict = function () { + $.fn.modal = old + return this + } + + + // MODAL DATA-API + // ============== + + $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { + var $this = $(this) + var href = $this.attr('href') + var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7 + var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) + + if ($this.is('a')) e.preventDefault() + + $target + .modal(option, this) + .one('hide', function () { + $this.is(':visible') && $this.trigger('focus') + }) + }) + + $(document) + .on('show.bs.modal', '.modal', function () { $(document.body).addClass('modal-open') }) + .on('hidden.bs.modal', '.modal', function () { $(document.body).removeClass('modal-open') }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: tooltip.js v3.1.1 + * http://getbootstrap.com/javascript/#tooltip + * Inspired by the original jQuery.tipsy by Jason Frame + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // TOOLTIP PUBLIC CLASS DEFINITION + // =============================== + + var Tooltip = function (element, options) { + this.type = + this.options = + this.enabled = + this.timeout = + this.hoverState = + this.$element = null + + this.init('tooltip', element, options) + } + + Tooltip.DEFAULTS = { + animation: true, + placement: 'top', + selector: false, + template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>', + trigger: 'hover focus', + title: '', + delay: 0, + html: false, + container: false + } + + Tooltip.prototype.init = function (type, element, options) { + this.enabled = true + this.type = type + this.$element = $(element) + this.options = this.getOptions(options) + + var triggers = this.options.trigger.split(' ') + + for (var i = triggers.length; i--;) { + var trigger = triggers[i] + + if (trigger == 'click') { + this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) + } else if (trigger != 'manual') { + var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' + var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' + + this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) + this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) + } + } + + this.options.selector ? + (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : + this.fixTitle() + } + + Tooltip.prototype.getDefaults = function () { + return Tooltip.DEFAULTS + } + + Tooltip.prototype.getOptions = function (options) { + options = $.extend({}, this.getDefaults(), this.$element.data(), options) + + if (options.delay && typeof options.delay == 'number') { + options.delay = { + show: options.delay, + hide: options.delay + } + } + + return options + } + + Tooltip.prototype.getDelegateOptions = function () { + var options = {} + var defaults = this.getDefaults() + + this._options && $.each(this._options, function (key, value) { + if (defaults[key] != value) options[key] = value + }) + + return options + } + + Tooltip.prototype.enter = function (obj) { + var self = obj instanceof this.constructor ? + obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) + + clearTimeout(self.timeout) + + self.hoverState = 'in' + + if (!self.options.delay || !self.options.delay.show) return self.show() + + self.timeout = setTimeout(function () { + if (self.hoverState == 'in') self.show() + }, self.options.delay.show) + } + + Tooltip.prototype.leave = function (obj) { + var self = obj instanceof this.constructor ? + obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) + + clearTimeout(self.timeout) + + self.hoverState = 'out' + + if (!self.options.delay || !self.options.delay.hide) return self.hide() + + self.timeout = setTimeout(function () { + if (self.hoverState == 'out') self.hide() + }, self.options.delay.hide) + } + + Tooltip.prototype.show = function () { + var e = $.Event('show.bs.' + this.type) + + if (this.hasContent() && this.enabled) { + this.$element.trigger(e) + + if (e.isDefaultPrevented()) return + var that = this; + + var $tip = this.tip() + + this.setContent() + + if (this.options.animation) $tip.addClass('fade') + + var placement = typeof this.options.placement == 'function' ? + this.options.placement.call(this, $tip[0], this.$element[0]) : + this.options.placement + + var autoToken = /\s?auto?\s?/i + var autoPlace = autoToken.test(placement) + if (autoPlace) placement = placement.replace(autoToken, '') || 'top' + + $tip + .detach() + .css({ top: 0, left: 0, display: 'block' }) + .addClass(placement) + + this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) + + var pos = this.getPosition() + var actualWidth = $tip[0].offsetWidth + var actualHeight = $tip[0].offsetHeight + + if (autoPlace) { + var $parent = this.$element.parent() + + var orgPlacement = placement + var docScroll = document.documentElement.scrollTop || document.body.scrollTop + var parentWidth = this.options.container == 'body' ? window.innerWidth : $parent.outerWidth() + var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight() + var parentLeft = this.options.container == 'body' ? 0 : $parent.offset().left + + placement = placement == 'bottom' && pos.top + pos.height + actualHeight - docScroll > parentHeight ? 'top' : + placement == 'top' && pos.top - docScroll - actualHeight < 0 ? 'bottom' : + placement == 'right' && pos.right + actualWidth > parentWidth ? 'left' : + placement == 'left' && pos.left - actualWidth < parentLeft ? 'right' : + placement + + $tip + .removeClass(orgPlacement) + .addClass(placement) + } + + var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) + + this.applyPlacement(calculatedOffset, placement) + this.hoverState = null + + var complete = function() { + that.$element.trigger('shown.bs.' + that.type) + } + + $.support.transition && this.$tip.hasClass('fade') ? + $tip + .one($.support.transition.end, complete) + .emulateTransitionEnd(150) : + complete() + } + } + + Tooltip.prototype.applyPlacement = function (offset, placement) { + var replace + var $tip = this.tip() + var width = $tip[0].offsetWidth + var height = $tip[0].offsetHeight + + // manually read margins because getBoundingClientRect includes difference + var marginTop = parseInt($tip.css('margin-top'), 10) + var marginLeft = parseInt($tip.css('margin-left'), 10) + + // we must check for NaN for ie 8/9 + if (isNaN(marginTop)) marginTop = 0 + if (isNaN(marginLeft)) marginLeft = 0 + + offset.top = offset.top + marginTop + offset.left = offset.left + marginLeft + + // $.fn.offset doesn't round pixel values + // so we use setOffset directly with our own function B-0 + $.offset.setOffset($tip[0], $.extend({ + using: function (props) { + $tip.css({ + top: Math.round(props.top), + left: Math.round(props.left) + }) + } + }, offset), 0) + + $tip.addClass('in') + + // check to see if placing tip in new offset caused the tip to resize itself + var actualWidth = $tip[0].offsetWidth + var actualHeight = $tip[0].offsetHeight + + if (placement == 'top' && actualHeight != height) { + replace = true + offset.top = offset.top + height - actualHeight + } + + if (/bottom|top/.test(placement)) { + var delta = 0 + + if (offset.left < 0) { + delta = offset.left * -2 + offset.left = 0 + + $tip.offset(offset) + + actualWidth = $tip[0].offsetWidth + actualHeight = $tip[0].offsetHeight + } + + this.replaceArrow(delta - width + actualWidth, actualWidth, 'left') + } else { + this.replaceArrow(actualHeight - height, actualHeight, 'top') + } + + if (replace) $tip.offset(offset) + } + + Tooltip.prototype.replaceArrow = function (delta, dimension, position) { + this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '') + } + + Tooltip.prototype.setContent = function () { + var $tip = this.tip() + var title = this.getTitle() + + $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) + $tip.removeClass('fade in top bottom left right') + } + + Tooltip.prototype.hide = function () { + var that = this + var $tip = this.tip() + var e = $.Event('hide.bs.' + this.type) + + function complete() { + if (that.hoverState != 'in') $tip.detach() + that.$element.trigger('hidden.bs.' + that.type) + } + + this.$element.trigger(e) + + if (e.isDefaultPrevented()) return + + $tip.removeClass('in') + + $.support.transition && this.$tip.hasClass('fade') ? + $tip + .one($.support.transition.end, complete) + .emulateTransitionEnd(150) : + complete() + + this.hoverState = null + + return this + } + + Tooltip.prototype.fixTitle = function () { + var $e = this.$element + if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { + $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') + } + } + + Tooltip.prototype.hasContent = function () { + return this.getTitle() + } + + Tooltip.prototype.getPosition = function () { + var el = this.$element[0] + return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : { + width: el.offsetWidth, + height: el.offsetHeight + }, this.$element.offset()) + } + + Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { + return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : + placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : + placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : + /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } + } + + Tooltip.prototype.getTitle = function () { + var title + var $e = this.$element + var o = this.options + + title = $e.attr('data-original-title') + || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) + + return title + } + + Tooltip.prototype.tip = function () { + return this.$tip = this.$tip || $(this.options.template) + } + + Tooltip.prototype.arrow = function () { + return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow') + } + + Tooltip.prototype.validate = function () { + if (!this.$element[0].parentNode) { + this.hide() + this.$element = null + this.options = null + } + } + + Tooltip.prototype.enable = function () { + this.enabled = true + } + + Tooltip.prototype.disable = function () { + this.enabled = false + } + + Tooltip.prototype.toggleEnabled = function () { + this.enabled = !this.enabled + } + + Tooltip.prototype.toggle = function (e) { + var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this + self.tip().hasClass('in') ? self.leave(self) : self.enter(self) + } + + Tooltip.prototype.destroy = function () { + clearTimeout(this.timeout) + this.hide().$element.off('.' + this.type).removeData('bs.' + this.type) + } + + + // TOOLTIP PLUGIN DEFINITION + // ========================= + + var old = $.fn.tooltip + + $.fn.tooltip = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.tooltip') + var options = typeof option == 'object' && option + + if (!data && option == 'destroy') return + if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.tooltip.Constructor = Tooltip + + + // TOOLTIP NO CONFLICT + // =================== + + $.fn.tooltip.noConflict = function () { + $.fn.tooltip = old + return this + } + +}(jQuery); + +/* ======================================================================== + * Bootstrap: popover.js v3.1.1 + * http://getbootstrap.com/javascript/#popovers + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // POPOVER PUBLIC CLASS DEFINITION + // =============================== + + var Popover = function (element, options) { + this.init('popover', element, options) + } + + if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') + + Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { + placement: 'right', + trigger: 'click', + content: '', + template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>' + }) + + + // NOTE: POPOVER EXTENDS tooltip.js + // ================================ + + Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) + + Popover.prototype.constructor = Popover + + Popover.prototype.getDefaults = function () { + return Popover.DEFAULTS + } + + Popover.prototype.setContent = function () { + var $tip = this.tip() + var title = this.getTitle() + var content = this.getContent() + + $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) + $tip.find('.popover-content')[ // we use append for html objects to maintain js events + this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' + ](content) + + $tip.removeClass('fade top bottom left right in') + + // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do + // this manually by checking the contents. + if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() + } + + Popover.prototype.hasContent = function () { + return this.getTitle() || this.getContent() + } + + Popover.prototype.getContent = function () { + var $e = this.$element + var o = this.options + + return $e.attr('data-content') + || (typeof o.content == 'function' ? + o.content.call($e[0]) : + o.content) + } + + Popover.prototype.arrow = function () { + return this.$arrow = this.$arrow || this.tip().find('.arrow') + } + + Popover.prototype.tip = function () { + if (!this.$tip) this.$tip = $(this.options.template) + return this.$tip + } + + + // POPOVER PLUGIN DEFINITION + // ========================= + + var old = $.fn.popover + + $.fn.popover = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.popover') + var options = typeof option == 'object' && option + + if (!data && option == 'destroy') return + if (!data) $this.data('bs.popover', (data = new Popover(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.popover.Constructor = Popover + + + // POPOVER NO CONFLICT + // =================== + + $.fn.popover.noConflict = function () { + $.fn.popover = old + return this + } + +}(jQuery); + +/* ======================================================================== + * Bootstrap: scrollspy.js v3.1.1 + * http://getbootstrap.com/javascript/#scrollspy + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // SCROLLSPY CLASS DEFINITION + // ========================== + + function ScrollSpy(element, options) { + var href + var process = $.proxy(this.process, this) + + this.$element = $(element).is('body') ? $(window) : $(element) + this.$body = $('body') + this.$scrollElement = this.$element.on('scroll.bs.scroll-spy.data-api', process) + this.options = $.extend({}, ScrollSpy.DEFAULTS, options) + this.selector = (this.options.target + || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + || '') + ' .nav li > a' + this.offsets = $([]) + this.targets = $([]) + this.activeTarget = null + + this.refresh() + this.process() + } + + ScrollSpy.DEFAULTS = { + offset: 10 + } + + ScrollSpy.prototype.refresh = function () { + var offsetMethod = this.$element[0] == window ? 'offset' : 'position' + + this.offsets = $([]) + this.targets = $([]) + + var self = this + var $targets = this.$body + .find(this.selector) + .map(function () { + var $el = $(this) + var href = $el.data('target') || $el.attr('href') + var $href = /^#./.test(href) && $(href) + + return ($href + && $href.length + && $href.is(':visible') + && [[ $href[offsetMethod]().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]]) || null + }) + .sort(function (a, b) { return a[0] - b[0] }) + .each(function () { + self.offsets.push(this[0]) + self.targets.push(this[1]) + }) + } + + ScrollSpy.prototype.process = function () { + var scrollTop = this.$scrollElement.scrollTop() + this.options.offset + var scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight + var maxScroll = scrollHeight - this.$scrollElement.height() + var offsets = this.offsets + var targets = this.targets + var activeTarget = this.activeTarget + var i + + if (scrollTop >= maxScroll) { + return activeTarget != (i = targets.last()[0]) && this.activate(i) + } + + if (activeTarget && scrollTop <= offsets[0]) { + return activeTarget != (i = targets[0]) && this.activate(i) + } + + for (i = offsets.length; i--;) { + activeTarget != targets[i] + && scrollTop >= offsets[i] + && (!offsets[i + 1] || scrollTop <= offsets[i + 1]) + && this.activate( targets[i] ) + } + } + + ScrollSpy.prototype.activate = function (target) { + this.activeTarget = target + + $(this.selector) + .parentsUntil(this.options.target, '.active') + .removeClass('active') + + var selector = this.selector + + '[data-target="' + target + '"],' + + this.selector + '[href="' + target + '"]' + + var active = $(selector) + .parents('li') + .addClass('active') + + if (active.parent('.dropdown-menu').length) { + active = active + .closest('li.dropdown') + .addClass('active') + } + + active.trigger('activate.bs.scrollspy') + } + + + // SCROLLSPY PLUGIN DEFINITION + // =========================== + + var old = $.fn.scrollspy + + $.fn.scrollspy = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.scrollspy') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.scrollspy.Constructor = ScrollSpy + + + // SCROLLSPY NO CONFLICT + // ===================== + + $.fn.scrollspy.noConflict = function () { + $.fn.scrollspy = old + return this + } + + + // SCROLLSPY DATA-API + // ================== + + $(window).on('load', function () { + $('[data-spy="scroll"]').each(function () { + var $spy = $(this) + $spy.scrollspy($spy.data()) + }) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: tab.js v3.1.1 + * http://getbootstrap.com/javascript/#tabs + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // TAB CLASS DEFINITION + // ==================== + + var Tab = function (element) { + this.element = $(element) + } + + Tab.prototype.show = function () { + var $this = this.element + var $ul = $this.closest('ul:not(.dropdown-menu)') + var selector = $this.data('target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + if ($this.parent('li').hasClass('active')) return + + var previous = $ul.find('.active:last a')[0] + var e = $.Event('show.bs.tab', { + relatedTarget: previous + }) + + $this.trigger(e) + + if (e.isDefaultPrevented()) return + + var $target = $(selector) + + this.activate($this.parent('li'), $ul) + this.activate($target, $target.parent(), function () { + $this.trigger({ + type: 'shown.bs.tab', + relatedTarget: previous + }) + }) + } + + Tab.prototype.activate = function (element, container, callback) { + var $active = container.find('> .active') + var transition = callback + && $.support.transition + && $active.hasClass('fade') + + function next() { + $active + .removeClass('active') + .find('> .dropdown-menu > .active') + .removeClass('active') + + element.addClass('active') + + if (transition) { + element[0].offsetWidth // reflow for transition + element.addClass('in') + } else { + element.removeClass('fade') + } + + if (element.parent('.dropdown-menu')) { + element.closest('li.dropdown').addClass('active') + } + + callback && callback() + } + + transition ? + $active + .one($.support.transition.end, next) + .emulateTransitionEnd(150) : + next() + + $active.removeClass('in') + } + + + // TAB PLUGIN DEFINITION + // ===================== + + var old = $.fn.tab + + $.fn.tab = function ( option ) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.tab') + + if (!data) $this.data('bs.tab', (data = new Tab(this))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.tab.Constructor = Tab + + + // TAB NO CONFLICT + // =============== + + $.fn.tab.noConflict = function () { + $.fn.tab = old + return this + } + + + // TAB DATA-API + // ============ + + $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { + e.preventDefault() + $(this).tab('show') + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: affix.js v3.1.1 + * http://getbootstrap.com/javascript/#affix + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // AFFIX CLASS DEFINITION + // ====================== + + var Affix = function (element, options) { + this.options = $.extend({}, Affix.DEFAULTS, options) + this.$window = $(window) + .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) + .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) + + this.$element = $(element) + this.affixed = + this.unpin = + this.pinnedOffset = null + + this.checkPosition() + } + + Affix.RESET = 'affix affix-top affix-bottom' + + Affix.DEFAULTS = { + offset: 0 + } + + Affix.prototype.getPinnedOffset = function () { + if (this.pinnedOffset) return this.pinnedOffset + this.$element.removeClass(Affix.RESET).addClass('affix') + var scrollTop = this.$window.scrollTop() + var position = this.$element.offset() + return (this.pinnedOffset = position.top - scrollTop) + } + + Affix.prototype.checkPositionWithEventLoop = function () { + setTimeout($.proxy(this.checkPosition, this), 1) + } + + Affix.prototype.checkPosition = function () { + if (!this.$element.is(':visible')) return + + var scrollHeight = $(document).height() + var scrollTop = this.$window.scrollTop() + var position = this.$element.offset() + var offset = this.options.offset + var offsetTop = offset.top + var offsetBottom = offset.bottom + + if (this.affixed == 'top') position.top += scrollTop + + if (typeof offset != 'object') offsetBottom = offsetTop = offset + if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) + if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) + + var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false : + offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' : + offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false + + if (this.affixed === affix) return + if (this.unpin) this.$element.css('top', '') + + var affixType = 'affix' + (affix ? '-' + affix : '') + var e = $.Event(affixType + '.bs.affix') + + this.$element.trigger(e) + + if (e.isDefaultPrevented()) return + + this.affixed = affix + this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null + + this.$element + .removeClass(Affix.RESET) + .addClass(affixType) + .trigger($.Event(affixType.replace('affix', 'affixed'))) + + if (affix == 'bottom') { + this.$element.offset({ top: scrollHeight - offsetBottom - this.$element.height() }) + } + } + + + // AFFIX PLUGIN DEFINITION + // ======================= + + var old = $.fn.affix + + $.fn.affix = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.affix') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.affix', (data = new Affix(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.affix.Constructor = Affix + + + // AFFIX NO CONFLICT + // ================= + + $.fn.affix.noConflict = function () { + $.fn.affix = old + return this + } + + + // AFFIX DATA-API + // ============== + + $(window).on('load', function () { + $('[data-spy="affix"]').each(function () { + var $spy = $(this) + var data = $spy.data() + + data.offset = data.offset || {} + + if (data.offsetBottom) data.offset.bottom = data.offsetBottom + if (data.offsetTop) data.offset.top = data.offsetTop + + $spy.affix(data) + }) + }) + +}(jQuery); +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/js/bootstrap.min.js b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/static/js/bootstrap.min.js @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.1.1 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(jQuery),+function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function c(){f.trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one(a.support.transition.end,c).emulateTransitionEnd(150):c())};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("bs.alert");e||d.data("bs.alert",e=new c(this)),"string"==typeof b&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.bs.alert.data-api",b,c.prototype.close)}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.isLoading=!1};b.DEFAULTS={loadingText:"loading..."},b.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",f.resetText||d.data("resetText",d[e]()),d[e](f[b]||this.options[b]),setTimeout(a.proxy(function(){"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},b.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}a&&this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof c&&c;e||d.data("bs.button",e=new b(this,f)),"toggle"==c?e.toggle():c&&e.setState(c)})},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.bs.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle"),b.preventDefault()})}(jQuery),+function(a){"use strict";var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},b.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},b.prototype.getActiveIndex=function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},b.prototype.to=function(b){var c=this,d=this.getActiveIndex();return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},b.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},b.prototype.next=function(){return this.sliding?void 0:this.slide("next")},b.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},b.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}if(e.hasClass("active"))return this.sliding=!1;var j=a.Event("slide.bs.carousel",{relatedTarget:e[0],direction:g});return this.$element.trigger(j),j.isDefaultPrevented()?void 0:(this.sliding=!0,f&&this.pause(),this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid.bs.carousel",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")})),a.support.transition&&this.$element.hasClass("slide")?(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid.bs.carousel")},0)}).emulateTransitionEnd(1e3*d.css("transition-duration").slice(0,-1))):(d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid.bs.carousel")),f&&this.cycle(),this)};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c),g="string"==typeof c?c:f.slide;e||d.data("bs.carousel",e=new b(this,f)),"number"==typeof c?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c,d=a(this),e=a(d.attr("data-target")||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),d.data()),g=d.attr("data-slide-to");g&&(f.interval=!1),e.carousel(f),(g=d.attr("data-slide-to"))&&e.data("bs.carousel").to(g),b.preventDefault()}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var b=a(this);b.carousel(b.data())})})}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0},b.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},b.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b=a.Event("show.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.$parent&&this.$parent.find("> .panel > .in");if(c&&c.length){var d=c.data("bs.collapse");if(d&&d.transitioning)return;c.collapse("hide"),d||c.data("bs.collapse",null)}var e=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[e](0),this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("collapse in")[e]("auto"),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return f.call(this);var g=a.camelCase(["scroll",e].join("-"));this.$element.one(a.support.transition.end,a.proxy(f,this)).emulateTransitionEnd(350)[e](this.$element[0][g])}}},b.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?void this.$element[c](0).one(a.support.transition.end,a.proxy(d,this)).emulateTransitionEnd(350):d.call(this)}}},b.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);!e&&f.toggle&&"show"==c&&(c=!c),e||d.data("bs.collapse",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.bs.collapse.data-api","[data-toggle=collapse]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.collapse"),h=g?"toggle":d.data(),i=d.attr("data-parent"),j=i&&a(i);g&&g.transitioning||(j&&j.find('[data-toggle=collapse][data-parent="'+i+'"]').not(d).addClass("collapsed"),d[f.hasClass("in")?"addClass":"removeClass"]("collapsed")),f.collapse(h)})}(jQuery),+function(a){"use strict";function b(b){a(d).remove(),a(e).each(function(){var d=c(a(this)),e={relatedTarget:this};d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown",e)),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown",e))})}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}var d=".dropdown-backdrop",e="[data-toggle=dropdown]",f=function(b){a(b).on("click.bs.dropdown",this.toggle)};f.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;f.toggleClass("open").trigger("shown.bs.dropdown",h),e.trigger("focus")}return!1}},f.prototype.keydown=function(b){if(/(38|40|27)/.test(b.keyCode)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var f=c(d),g=f.hasClass("open");if(!g||g&&27==b.keyCode)return 27==b.which&&f.find(e).trigger("focus"),d.trigger("click");var h=" li:not(.divider):visible a",i=f.find("[role=menu]"+h+", [role=listbox]"+h);if(i.length){var j=i.index(i.filter(":focus"));38==b.keyCode&&j>0&&j--,40==b.keyCode&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var g=a.fn.dropdown;a.fn.dropdown=function(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new f(this)),"string"==typeof b&&d[b].call(c)})},a.fn.dropdown.Constructor=f,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=g,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",e,f.prototype.toggle).on("keydown.bs.dropdown.data-api",e+", [role=menu], [role=listbox]",f.prototype.keydown)}(jQuery),+function(a){"use strict";var b=function(b,c){this.options=c,this.$element=a(b),this.$backdrop=this.isShown=null,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};b.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},b.prototype.toggle=function(a){return this[this.isShown?"hide":"show"](a)},b.prototype.show=function(b){var c=this,d=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(d),this.isShown||d.isDefaultPrevented()||(this.isShown=!0,this.escape(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.backdrop(function(){var d=a.support.transition&&c.$element.hasClass("fade");c.$element.parent().length||c.$element.appendTo(document.body),c.$element.show().scrollTop(0),d&&c.$element[0].offsetWidth,c.$element.addClass("in").attr("aria-hidden",!1),c.enforceFocus();var e=a.Event("shown.bs.modal",{relatedTarget:b});d?c.$element.find(".modal-dialog").one(a.support.transition.end,function(){c.$element.trigger("focus").trigger(e)}).emulateTransitionEnd(300):c.$element.trigger("focus").trigger(e)}))},b.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one(a.support.transition.end,a.proxy(this.hideModal,this)).emulateTransitionEnd(300):this.hideModal())},b.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},b.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keyup.dismiss.bs.modal")},b.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden.bs.modal")})},b.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},b.prototype.backdrop=function(b){var c=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var d=a.support.transition&&c;if(this.$backdrop=a('<div class="modal-backdrop '+c+'" />').appendTo(document.body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),d&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;d?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()):b&&b()};var c=a.fn.modal;a.fn.modal=function(c,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},b.DEFAULTS,e.data(),"object"==typeof c&&c);f||e.data("bs.modal",f=new b(this,g)),"string"==typeof c?f[c](d):g.show&&f.show(d)})},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());c.is("a")&&b.preventDefault(),e.modal(f,this).one("hide",function(){c.is(":visible")&&c.trigger("focus")})}),a(document).on("show.bs.modal",".modal",function(){a(document.body).addClass("modal-open")}).on("hidden.bs.modal",".modal",function(){a(document.body).removeClass("modal-open")})}(jQuery),+function(a){"use strict";var b=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};b.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},b.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},b.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},b.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show()},b.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},b.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){if(this.$element.trigger(b),b.isDefaultPrevented())return;var c=this,d=this.tip();this.setContent(),this.options.animation&&d.addClass("fade");var e="function"==typeof this.options.placement?this.options.placement.call(this,d[0],this.$element[0]):this.options.placement,f=/\s?auto?\s?/i,g=f.test(e);g&&(e=e.replace(f,"")||"top"),d.detach().css({top:0,left:0,display:"block"}).addClass(e),this.options.container?d.appendTo(this.options.container):d.insertAfter(this.$element);var h=this.getPosition(),i=d[0].offsetWidth,j=d[0].offsetHeight;if(g){var k=this.$element.parent(),l=e,m=document.documentElement.scrollTop||document.body.scrollTop,n="body"==this.options.container?window.innerWidth:k.outerWidth(),o="body"==this.options.container?window.innerHeight:k.outerHeight(),p="body"==this.options.container?0:k.offset().left;e="bottom"==e&&h.top+h.height+j-m>o?"top":"top"==e&&h.top-m-j<0?"bottom":"right"==e&&h.right+i>n?"left":"left"==e&&h.left-i<p?"right":e,d.removeClass(l).addClass(e)}var q=this.getCalculatedOffset(e,h,i,j);this.applyPlacement(q,e),this.hoverState=null;var r=function(){c.$element.trigger("shown.bs."+c.type)};a.support.transition&&this.$tip.hasClass("fade")?d.one(a.support.transition.end,r).emulateTransitionEnd(150):r()}},b.prototype.applyPlacement=function(b,c){var d,e=this.tip(),f=e[0].offsetWidth,g=e[0].offsetHeight,h=parseInt(e.css("margin-top"),10),i=parseInt(e.css("margin-left"),10);isNaN(h)&&(h=0),isNaN(i)&&(i=0),b.top=b.top+h,b.left=b.left+i,a.offset.setOffset(e[0],a.extend({using:function(a){e.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),e.addClass("in");var j=e[0].offsetWidth,k=e[0].offsetHeight;if("top"==c&&k!=g&&(d=!0,b.top=b.top+g-k),/bottom|top/.test(c)){var l=0;b.left<0&&(l=-2*b.left,b.left=0,e.offset(b),j=e[0].offsetWidth,k=e[0].offsetHeight),this.replaceArrow(l-f+j,j,"left")}else this.replaceArrow(k-g,k,"top");d&&e.offset(b)},b.prototype.replaceArrow=function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},b.prototype.hide=function(){function b(){"in"!=c.hoverState&&d.detach(),c.$element.trigger("hidden.bs."+c.type)}var c=this,d=this.tip(),e=a.Event("hide.bs."+this.type);return this.$element.trigger(e),e.isDefaultPrevented()?void 0:(d.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d.one(a.support.transition.end,b).emulateTransitionEnd(150):b(),this.hoverState=null,this)},b.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},b.prototype.hasContent=function(){return this.getTitle()},b.prototype.getPosition=function(){var b=this.$element[0];return a.extend({},"function"==typeof b.getBoundingClientRect?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},b.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},b.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},b.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},b.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},b.prototype.enable=function(){this.enabled=!0},b.prototype.disable=function(){this.enabled=!1},b.prototype.toggleEnabled=function(){this.enabled=!this.enabled},b.prototype.toggle=function(b){var c=b?a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type):this;c.tip().hasClass("in")?c.leave(c):c.enter(c)},b.prototype.destroy=function(){clearTimeout(this.timeout),this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof c&&c;(e||"destroy"!=c)&&(e||d.data("bs.tooltip",e=new b(this,f)),"string"==typeof c&&e[c]())})},a.fn.tooltip.Constructor=b,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=c,this}}(jQuery),+function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");b.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),b.prototype.constructor=b,b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},b.prototype.hasContent=function(){return this.getTitle()||this.getContent()},b.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},b.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof c&&c;(e||"destroy"!=c)&&(e||d.data("bs.popover",e=new b(this,f)),"string"==typeof c&&e[c]())})},a.fn.popover.Constructor=b,a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(jQuery),+function(a){"use strict";function b(c,d){var e,f=a.proxy(this.process,this);this.$element=a(a(c).is("body")?window:c),this.$body=a("body"),this.$scrollElement=this.$element.on("scroll.bs.scroll-spy.data-api",f),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||(e=a(c).attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.offsets=a([]),this.targets=a([]),this.activeTarget=null,this.refresh(),this.process()}b.DEFAULTS={offset:10},b.prototype.refresh=function(){var b=this.$element[0]==window?"offset":"position";this.offsets=a([]),this.targets=a([]);{var c=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[b]().top+(!a.isWindow(c.$scrollElement.get(0))&&c.$scrollElement.scrollTop()),e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){c.offsets.push(this[0]),c.targets.push(this[1])})}},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,d=c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(b>=d)return g!=(a=f.last()[0])&&this.activate(a);if(g&&b<=e[0])return g!=(a=f[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parentsUntil(this.options.target,".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(jQuery),+function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.parent("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},b.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e).emulateTransitionEnd(150):e(),f.removeClass("in")};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new b(this)),"string"==typeof c&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(jQuery),+function(a){"use strict";var b=function(c,d){this.options=a.extend({},b.DEFAULTS,d),this.$window=a(window).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(c),this.affixed=this.unpin=this.pinnedOffset=null,this.checkPosition()};b.RESET="affix affix-top affix-bottom",b.DEFAULTS={offset:0},b.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(b.RESET).addClass("affix");var a=this.$window.scrollTop(),c=this.$element.offset();return this.pinnedOffset=c.top-a},b.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},b.prototype.checkPosition=function(){if(this.$element.is(":visible")){var c=a(document).height(),d=this.$window.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"top"==this.affixed&&(e.top+=d),"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top(this.$element)),"function"==typeof h&&(h=f.bottom(this.$element));var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=c-h?"bottom":null!=g&&g>=d?"top":!1;if(this.affixed!==i){this.unpin&&this.$element.css("top","");var j="affix"+(i?"-"+i:""),k=a.Event(j+".bs.affix");this.$element.trigger(k),k.isDefaultPrevented()||(this.affixed=i,this.unpin="bottom"==i?this.getPinnedOffset():null,this.$element.removeClass(b.RESET).addClass(j).trigger(a.Event(j.replace("affix","affixed"))),"bottom"==i&&this.$element.offset({top:c-h-this.$element.height()}))}}};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof c&&c;e||d.data("bs.affix",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(jQuery); +\ No newline at end of file diff --git a/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/theme.conf b/doc/sphinx/_exts/taler_sphinx_theme/guzzle_sphinx_theme/theme.conf @@ -0,0 +1,40 @@ +[theme] + +inherit = basic +stylesheet = guzzle.css + +[options] + +# Set to an html template to load custom HTML for the homepage +index_template = + +# Set the name of the project to appear in the left sidebar. +project_nav_name = + +# Path to a touch icon +touch_icon = + +# Set this value to enable Disqus comments +disqus_comments_shortname = + +# Set to enable google analytics +google_analytics_account = + +# Specify a base_url used to generate sitemap.xml links. If not specified, then +# no sitemap will be built. +base_url = + +# Allow a separate homepage from the "master_doc" +homepage = + +# Allow the project link to be overwritten to a custom URL. +projectlink = + +# The maximum depth of the global TOC; set it to -1 to allow unlimited depth +globaltoc_depth = 2 + +# If true, TOC entries that are not ancestors of the current page are collapsed +globaltoc_collapse = true + +# If true, the global TOC tree will also contain hidden entries +globaltoc_includehidden = true diff --git a/doc/sphinx/_exts/typescriptdomain.py b/doc/sphinx/_exts/typescriptdomain.py @@ -0,0 +1,587 @@ +""" +TypeScript domain. + +:copyright: Copyright 2019 by Taler Systems SA +:license: LGPLv3+ +:author: Florian Dold +""" + +import re + +from pathlib import Path + +from docutils import nodes +from typing import List, Optional, Iterable, Dict, Tuple +from typing import cast + +from pygments.lexers import get_lexer_by_name +from pygments.filter import Filter +from pygments.token import Literal, Text, Operator, Keyword, Name, Number +from pygments.token import Comment, Token, _TokenType +from pygments.token import * +from pygments.lexer import RegexLexer, bygroups, include +from pygments.formatters import HtmlFormatter + +from docutils import nodes +from docutils.nodes import Element, Node + +from sphinx.roles import XRefRole +from sphinx.domains import Domain, ObjType, Index +from sphinx.directives import directives +from sphinx.util.docutils import SphinxDirective +from sphinx.util.nodes import make_refnode +from sphinx.util import logging +from sphinx.highlighting import PygmentsBridge +from sphinx.builders.html import StandaloneHTMLBuilder +from sphinx.pygments_styles import SphinxStyle + +logger = logging.getLogger(__name__) + + +class TypeScriptDefinition(SphinxDirective): + """ + Directive for a code block with special highlighting or line numbering + settings. + """ + + has_content = True + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = False + option_spec = { + "force": directives.flag, + "linenos": directives.flag, + "dedent": int, + "lineno-start": int, + "emphasize-lines": directives.unchanged_required, + "caption": directives.unchanged_required, + "class": directives.class_option, + } + + def run(self) -> List[Node]: + document = self.state.document + code = "\n".join(self.content) + location = self.state_machine.get_source_and_line(self.lineno) + + linespec = self.options.get("emphasize-lines") + if linespec: + try: + nlines = len(self.content) + hl_lines = parselinenos(linespec, nlines) + if any(i >= nlines for i in hl_lines): + logger.warning( + __("line number spec is out of range(1-%d): %r") + % (nlines, self.options["emphasize-lines"]), + location=location, + ) + + hl_lines = [x + 1 for x in hl_lines if x < nlines] + except ValueError as err: + return [document.reporter.warning(err, line=self.lineno)] + else: + hl_lines = None + + if "dedent" in self.options: + location = self.state_machine.get_source_and_line(self.lineno) + lines = code.split("\n") + lines = dedent_lines(lines, self.options["dedent"], location=location) + code = "\n".join(lines) + + literal = nodes.literal_block(code, code) # type: Element + if "linenos" in self.options or "lineno-start" in self.options: + literal["linenos"] = True + literal["classes"] += self.options.get("class", []) + literal["force"] = "force" in self.options + literal["language"] = "tsref" + extra_args = literal["highlight_args"] = {} + if hl_lines is not None: + extra_args["hl_lines"] = hl_lines + if "lineno-start" in self.options: + extra_args["linenostart"] = self.options["lineno-start"] + self.set_source_info(literal) + + caption = self.options.get("caption") + if caption: + try: + literal = container_wrapper(self, literal, caption) + except ValueError as exc: + return [document.reporter.warning(exc, line=self.lineno)] + + tsid = "tsref-type-" + self.arguments[0] + literal["ids"].append(tsid) + + tsname = self.arguments[0] + ts = self.env.get_domain("ts") + ts.add_object("type", tsname, self.env.docname, tsid) + + return [literal] + + +class TypeScriptDomain(Domain): + """TypeScript domain.""" + + name = "ts" + label = "TypeScript" + + directives = { + "def": TypeScriptDefinition, + } + + roles = { + "type": XRefRole( + lowercase=False, warn_dangling=True, innernodeclass=nodes.inline + ), + } + + dangling_warnings = { + "type": "undefined TypeScript type: %(target)s", + } + + def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): + try: + info = self.objects[(str(typ), str(target))] + except KeyError: + logger.warn("type {}/{} not found".format(typ, target)) + return None + else: + anchor = "tsref-type-{}".format(str(target)) + title = typ.upper() + " " + target + return make_refnode(builder, fromdocname, info[0], anchor, contnode, title) + + def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): + """Resolve the pending_xref *node* with the given *target*. + + The reference comes from an "any" or similar role, which means that Sphinx + don't know the type. + + For now sphinxcontrib-httpdomain doesn't resolve any xref nodes. + + :return: + list of tuples ``('domain:role', newnode)``, where ``'domain:role'`` + is the name of a role that could have created the same reference, + """ + ret = [] + try: + info = self.objects[("type", str(target))] + except KeyError: + pass + else: + anchor = "tsref-type-{}".format(str(target)) + title = "TYPE" + " " + target + node = make_refnode(builder, fromdocname, info[0], anchor, contnode, title) + ret.append(("ts:type", node)) + return ret + + @property + def objects(self) -> Dict[Tuple[str, str], Tuple[str, str]]: + return self.data.setdefault( + "objects", {} + ) # (objtype, name) -> docname, labelid + + def add_object(self, objtype: str, name: str, docname: str, labelid: str) -> None: + self.objects[objtype, name] = (docname, labelid) + + +class BetterTypeScriptLexer(RegexLexer): + """ + For `TypeScript <https://www.typescriptlang.org/>`_ source code. + """ + + name = "TypeScript" + aliases = ["ts"] + filenames = ["*.ts"] + mimetypes = ["text/x-typescript"] + + flags = re.DOTALL + tokens = { + "commentsandwhitespace": [ + (r"\s+", Text), + (r"<!--", Comment), + (r"//.*?\n", Comment.Single), + (r"/\*.*?\*/", Comment.Multiline), + ], + "slashstartsregex": [ + include("commentsandwhitespace"), + ( + r"/(\\.|[^[/\\\n]|\[(\\.|[^\]\\\n])*])+/" r"([gim]+\b|\B)", + String.Regex, + "#pop", + ), + (r"(?=/)", Text, ("#pop", "badregex")), + (r"", Text, "#pop"), + ], + "badregex": [(r"\n", Text, "#pop")], + "typeexp": [ + (r"[a-zA-Z0-9_?.$]+", Keyword.Type), + (r"\s+", Text), + (r"[|]", Text), + (r"\n", Text, "#pop"), + (r";", Text, "#pop"), + (r"", Text, "#pop"), + ], + "root": [ + (r"^(?=\s|/|<!--)", Text, "slashstartsregex"), + include("commentsandwhitespace"), + ( + r"\+\+|--|~|&&|\?|:|\|\||\\(?=\n)|" + r"(<<|>>>?|==?|!=?|[-<>+*%&\|\^/])=?", + Operator, + "slashstartsregex", + ), + (r"[{(\[;,]", Punctuation, "slashstartsregex"), + (r"[})\].]", Punctuation), + ( + r"(for|in|while|do|break|return|continue|switch|case|default|if|else|" + r"throw|try|catch|finally|new|delete|typeof|instanceof|void|" + r"this)\b", + Keyword, + "slashstartsregex", + ), + ( + r"(var|let|const|with|function)\b", + Keyword.Declaration, + "slashstartsregex", + ), + ( + r"(abstract|boolean|byte|char|class|const|debugger|double|enum|export|" + r"extends|final|float|goto|implements|import|int|interface|long|native|" + r"package|private|protected|public|short|static|super|synchronized|throws|" + r"transient|volatile)\b", + Keyword.Reserved, + ), + (r"(true|false|null|NaN|Infinity|undefined)\b", Keyword.Constant), + ( + r"(Array|Boolean|Date|Error|Function|Math|netscape|" + r"Number|Object|Packages|RegExp|String|sun|decodeURI|" + r"decodeURIComponent|encodeURI|encodeURIComponent|" + r"Error|eval|isFinite|isNaN|parseFloat|parseInt|document|this|" + r"window)\b", + Name.Builtin, + ), + # Match stuff like: module name {...} + ( + r"\b(module)(\s*)(\s*[a-zA-Z0-9_?.$][\w?.$]*)(\s*)", + bygroups(Keyword.Reserved, Text, Name.Other, Text), + "slashstartsregex", + ), + # Match variable type keywords + (r"\b(string|bool|number)\b", Keyword.Type), + # Match stuff like: constructor + (r"\b(constructor|declare|interface|as|AS)\b", Keyword.Reserved), + # Match stuff like: super(argument, list) + ( + r"(super)(\s*)\(([a-zA-Z0-9,_?.$\s]+\s*)\)", + bygroups(Keyword.Reserved, Text), + "slashstartsregex", + ), + # Match stuff like: function() {...} + (r"([a-zA-Z_?.$][\w?.$]*)\(\) \{", Name.Other, "slashstartsregex"), + # Match stuff like: (function: return type) + ( + r"([a-zA-Z0-9_?.$][\w?.$]*)(\s*:\s*)", + bygroups(Name.Other, Text), + "typeexp", + ), + # Match stuff like: type Foo = Bar | Baz + ( + r"\b(type)(\s*)([a-zA-Z0-9_?.$]+)(\s*)(=)(\s*)", + bygroups(Keyword.Reserved, Text, Name.Other, Text, Operator, Text), + "typeexp", + ), + (r"[$a-zA-Z_][a-zA-Z0-9_]*", Name.Other), + (r"[0-9][0-9]*\.[0-9]+([eE][0-9]+)?[fd]?", Number.Float), + (r"0x[0-9a-fA-F]+", Number.Hex), + (r"[0-9]+", Number.Integer), + (r'"(\\\\|\\"|[^"])*"', String.Double), + (r"'(\\\\|\\'|[^'])*'", String.Single), + ], + } + + +# Map from token id to props. +# Properties can't be added to tokens +# since they derive from Python's tuple. +token_props = {} + + +class LinkFilter(Filter): + def __init__(self, app, **options): + self.app = app + Filter.__init__(self, **options) + + def _filter_one_literal(self, ttype, value): + last = 0 + for m in re.finditer(literal_reg, value): + pre = value[last : m.start()] + if pre: + yield ttype, pre + t = copy_token(ttype) + tok_setprop(t, "is_literal", True) + yield t, m.group(1) + last = m.end() + post = value[last:] + if post: + yield ttype, post + + def filter(self, lexer, stream): + for ttype, value in stream: + if ttype in Token.Keyword.Type: + t = copy_token(ttype) + tok_setprop(t, "xref", value.strip()) + tok_setprop(t, "is_identifier", True) + yield t, value + elif ttype in Token.Comment: + last = 0 + for m in re.finditer(link_reg, value): + pre = value[last : m.start()] + if pre: + yield from self._filter_one_literal(ttype, pre) + t = copy_token(ttype) + x1, x2 = m.groups() + x0 = m.group(0) + if x2 is None: + caption = x1.strip() + xref = x1.strip() + else: + caption = x1.strip() + xref = x2.strip() + tok_setprop(t, "xref", xref) + tok_setprop(t, "caption", caption) + if x0.endswith("_"): + tok_setprop(t, "trailing_underscore", True) + yield t, m.group(1) + last = m.end() + post = value[last:] + if post: + yield from self._filter_one_literal(ttype, post) + else: + yield ttype, value + + +_escape_html_table = { + ord("&"): u"&amp;", + ord("<"): u"&lt;", + ord(">"): u"&gt;", + ord('"'): u"&quot;", + ord("'"): u"&#39;", +} + + +class LinkingHtmlFormatter(HtmlFormatter): + def __init__(self, **kwargs): + super(LinkingHtmlFormatter, self).__init__(**kwargs) + self._builder = kwargs["_builder"] + self._bridge = kwargs["_bridge"] + + def _get_value(self, value, tok): + xref = tok_getprop(tok, "xref") + caption = tok_getprop(tok, "caption") + + if tok_getprop(tok, "is_literal"): + return '<span style="font-weight: bolder">%s</span>' % (value,) + + if tok_getprop(tok, "trailing_underscore"): + logger.warn( + "{}:{}: code block contains xref to '{}' with unsupported trailing underscore".format( + self._bridge.path, self._bridge.line, xref + ) + ) + + if tok_getprop(tok, "is_identifier"): + if xref.startswith('"'): + return value + if re.match("^[0-9]+$", xref) is not None: + return value + if xref in ( + "number", + "object", + "string", + "boolean", + "any", + "true", + "false", + "null", + "undefined", + "Array", + "unknown", + ): + return value + + if self._bridge.docname is None: + return value + if xref is None: + return value + content = caption if caption is not None else value + ts = self._builder.env.get_domain("ts") + r1 = ts.objects.get(("type", xref), None) + if r1 is not None: + rel_uri = ( + self._builder.get_relative_uri(self._bridge.docname, r1[0]) + + "#" + + r1[1] + ) + return ( + '<a style="color:inherit;text-decoration:underline" href="%s">%s</a>' + % (rel_uri, content) + ) + + std = self._builder.env.get_domain("std") + r2 = std.labels.get(xref.lower(), None) + if r2 is not None: + rel_uri = ( + self._builder.get_relative_uri(self._bridge.docname, r2[0]) + + "#" + + r2[1] + ) + return ( + '<a style="color:inherit;text-decoration:underline" href="%s">%s</a>' + % (rel_uri, content) + ) + r3 = std.anonlabels.get(xref.lower(), None) + if r3 is not None: + rel_uri = ( + self._builder.get_relative_uri(self._bridge.docname, r3[0]) + + "#" + + r3[1] + ) + return ( + '<a style="color:inherit;text-decoration:underline" href="%s">%s</a>' + % (rel_uri, content) + ) + + logger.warn( + "{}:{}: code block contains unresolved xref '{}'".format( + self._bridge.path, self._bridge.line, xref + ) + ) + + return value + + def _fmt(self, value, tok): + cls = self._get_css_class(tok) + value = self._get_value(value, tok) + if cls is None or cls == "": + return value + return '<span class="%s">%s</span>' % (cls, value) + + def _format_lines(self, tokensource): + """ + Just format the tokens, without any wrapping tags. + Yield individual lines. + """ + lsep = self.lineseparator + escape_table = _escape_html_table + + line = "" + for ttype, value in tokensource: + link = get_annotation(ttype, "link") + + parts = value.translate(escape_table).split("\n") + + if len(parts) == 0: + # empty token, usually should not happen + pass + elif len(parts) == 1: + # no newline before or after token + line += self._fmt(parts[0], ttype) + else: + line += self._fmt(parts[0], ttype) + yield 1, line + lsep + for part in parts[1:-1]: + yield 1, self._fmt(part, ttype) + lsep + line = self._fmt(parts[-1], ttype) + + if line: + yield 1, line + lsep + + +class MyPygmentsBridge(PygmentsBridge): + def __init__(self, builder, trim_doctest_flags): + self.dest = "html" + self.trim_doctest_flags = trim_doctest_flags + self.formatter_args = { + "style": SphinxStyle, + "_builder": builder, + "_bridge": self, + } + self.formatter = LinkingHtmlFormatter + self.builder = builder + self.path = None + self.line = None + self.docname = None + + def highlight_block( + self, source, lang, opts=None, force=False, location=None, **kwargs + ): + if isinstance(location, tuple): + docname, line = location + self.line = line + self.path = self.builder.env.doc2path(docname) + self.docname = docname + elif isinstance(location, Element): + self.line = location.line + self.path = location.source + self.docname = self.builder.env.path2doc(self.path) + return super().highlight_block(source, lang, opts, force, location, **kwargs) + + +class MyHtmlBuilder(StandaloneHTMLBuilder): + name = "html-linked" + + def init_highlighter(self): + if self.config.pygments_style is not None: + style = self.config.pygments_style + elif self.theme: + style = self.theme.get_confstr("theme", "pygments_style", "none") + else: + style = "sphinx" + self.highlighter = MyPygmentsBridge(self, self.config.trim_doctest_flags) + self.dark_highlighter = None + + +def get_annotation(tok, key): + if not hasattr(tok, "kv"): + return None + return tok.kv.get(key) + + +def copy_token(tok): + new_tok = _TokenType(tok) + # This part is very fragile against API changes ... + new_tok.subtypes = set(tok.subtypes) + new_tok.parent = tok.parent + return new_tok + + +def tok_setprop(tok, key, value): + tokid = id(tok) + e = token_props.get(tokid) + if e is None: + e = token_props[tokid] = (tok, {}) + _, kv = e + kv[key] = value + + +def tok_getprop(tok, key): + tokid = id(tok) + e = token_props.get(tokid) + if e is None: + return None + _, kv = e + return kv.get(key) + + +link_reg = re.compile(r"(?<!`)`([^`<]+)\s*(?:<([^>]+)>)?\s*`_?") +literal_reg = re.compile(r"``([^`]+)``") + + +def setup(app): + + class TsrefLexer(BetterTypeScriptLexer): + def __init__(self, **options): + super().__init__(**options) + self.add_filter(LinkFilter(app)) + + app.add_lexer("tsref", TsrefLexer) + app.add_domain(TypeScriptDomain) + app.add_builder(MyHtmlBuilder) diff --git a/doc/sphinx/appendix.rst b/doc/sphinx/appendix.rst @@ -0,0 +1,28 @@ +.. + This file is part of Frosix. + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + + @author Joel Urech + +======== +Appendix +======== + + +Code Documentation over public C header files +============================================= + + +Self Declaration +================ +\ No newline at end of file diff --git a/doc/sphinx/conf.py b/doc/sphinx/conf.py @@ -0,0 +1,307 @@ +""" + This file is part of Anastasis. + Copyright (C) 2021 Anastasis SARL + + Anastasis is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + + @author Christian Grothoff +""" +# -*- coding: utf-8 -*- +# +# neuro documentation build configuration file, created by +# sphinx-quickstart on Sat May 31 13:11:06 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +sys.path.append(os.path.abspath("_exts")) + +import taler_sphinx_theme + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = "2.2.0" + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "ebicsdomain", + "typescriptdomain", + "taler_sphinx_theme", + "sphinx.ext.todo", + "sphinx.ext.imgmath", + "httpdomain.httpdomain", + "recommonmark", + "sphinx.ext.graphviz", +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +source_suffix = { + ".rst": "restructuredtext", + ".txt": "markdown", + ".md": "markdown", +} + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = "index" + +# General information about the project. +project = "Frosix" +copyright = "2022-2023 Frosix (GPLv3+ or GFDL 1.3+)" +author = "Joel Urech" + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = "0.0" +# The full version, including alpha/beta/rc tags. +release = "0.0.1" + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# today = '' +# Else, today_fmt is used as the format for a strftime call. +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [ + "_build", + "_exts", + "cf", + "prebuilt", + "**/README.md", + "extract-tsdefs", +] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +default_role = "ts:type" + +# If true, '()' will be appended to :func: etc. cross-reference text. +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = "taler_sphinx_theme" +html_theme_path = taler_sphinx_theme.html_theme_path() + +html_sidebars = {"**": ["logo-text.html", "globaltoc.html", "searchbox.html"]} + +html_theme_options = { + # Set the name of the project to appear in the sidebar + "project_nav_name": "Frosix", + "globaltoc_depth": 4, + "globaltoc_includehidden": False, +} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +# html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +# html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {} + +# If false, no module index is generated. +# html_domain_indices = True + +# If false, no index is generated. +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + #'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +#latex_documents = [()] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# latex_use_parts = False + +# If true, show page references after internal links. +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = ["fdl-1.3"] + +# If false, no module index is generated. +# latex_domain_indices = True + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +#man_pages = [()] + +# If true, show URL addresses after external links. +# man_show_urls = False + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +#texinfo_documents = [()] + +# Documents to append as an appendix to all manuals. +# texinfo_appendices = [] + +# If false, no module index is generated. +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# texinfo_no_detailmenu = False + +# The output format for Graphviz when building HTML files. +# This must be either 'png' or 'svg'; the default is 'png'. +graphviz_output_format = "svg" + +myst_heading_anchors = 3 + +myst_enable_extensions = [ + "amsmath", + "colon_fence", + "deflist", + "dollarmath", + "fieldlist", + "html_admonition", + "html_image", + "linkify", + "replacements", + "smartquotes", + "strikethrough", + "substitution", + "tasklist", +] diff --git a/doc/sphinx/fdl-1.3.rst b/doc/sphinx/fdl-1.3.rst @@ -0,0 +1,453 @@ +.. _gnu-fdl-1.3: + +GNU Free Documentation License +============================== + +Version 1.3, 3 November 2008 + +Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, +Inc. \ https://fsf.org/ + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +0. PREAMBLE +----------- + +The purpose of this License is to make a manual, textbook, or other +functional and useful document “free” in the sense of freedom: to assure +everyone the effective freedom to copy and redistribute it, with or +without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible for +modifications made by others. + +This License is a kind of “copyleft”, which means that derivative works +of the document must themselves be free in the same sense. It +complements the GNU Affero General Public License, which is a copyleft license +designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free program +should come with manuals providing the same freedoms that the software +does. But this License is not limited to software manuals; it can be +used for any textual work, regardless of subject matter or whether it is +published as a printed book. We recommend this License principally for +works whose purpose is instruction or reference. + +1. APPLICABILITY AND DEFINITIONS +-------------------------------- + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The “Document”, below, refers +to any such manual or work. Any member of the public is a licensee, and +is addressed as “you”. You accept the license if you copy, modify or +distribute the work in a way requiring permission under copyright law. + +A “Modified Version” of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A “Secondary Section” is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document’s overall subject +(or to related matters) and contains nothing that could fall directly +within that overall subject. (Thus, if the Document is in part a +textbook of mathematics, a Secondary Section may not explain any +mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding them. + +The “Invariant Sections” are certain Secondary Sections whose titles are +designated, as being those of Invariant Sections, in the notice that +says that the Document is released under this License. If a section does +not fit the above definition of Secondary then it is not allowed to be +designated as Invariant. The Document may contain zero Invariant +Sections. If the Document does not identify any Invariant Sections then +there are none. + +The “Cover Texts” are certain short passages of text that are listed, as +Front-Cover Texts or Back-Cover Texts, in the notice that says that the +Document is released under this License. A Front-Cover Text may be at +most 5 words, and a Back-Cover Text may be at most 25 words. + +A “Transparent” copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the general +public, that is suitable for revising the document straightforwardly +with generic text editors or (for images composed of pixels) generic +paint programs or (for drawings) some widely available drawing editor, +and that is suitable for input to text formatters or for automatic +translation to a variety of formats suitable for input to text +formatters. A copy made in an otherwise Transparent file format whose +markup, or absence of markup, has been arranged to thwart or discourage +subsequent modification by readers is not Transparent. An image format +is not Transparent if used for any substantial amount of text. A copy +that is not “Transparent” is called “Opaque”. + +Examples of suitable formats for Transparent copies include plain ASCII +without markup, Texinfo input format, LaTeX input format, SGML or XML +using a publicly available DTD, and standard-conforming simple HTML, +PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the machine-generated +HTML, PostScript or PDF produced by some word processors for output +purposes only. + +The “Title Page” means, for a printed book, the title page itself, plus +such following pages as are needed to hold, legibly, the material this +License requires to appear in the title page. For works in formats which +do not have any title page as such, “Title Page” means the text near the +most prominent appearance of the work’s title, preceding the beginning +of the body of the text. + +The “publisher” means any person or entity that distributes copies of +the Document to the public. + +A section “Entitled XYZ” means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as “Acknowledgements”, +“Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of +such a section when you modify the Document means that it remains a +section “Entitled XYZ” according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this License, +but only as regards disclaiming warranties: any other implication that +these Warranty Disclaimers may have is void and has no effect on the +meaning of this License. + +2. VERBATIM COPYING +------------------- + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies to +the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further copying +of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + +3. COPYING IN QUANTITY +---------------------- + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document’s license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover Texts: +Front-Cover Texts on the front cover, and Back-Cover Texts on the back +cover. Both covers must also clearly and legibly identify you as the +publisher of these copies. The front cover must present the full title +with all words of the title equally prominent and visible. You may add +other material on the covers in addition. Copying with changes limited +to the covers, as long as they preserve the title of the Document and +satisfy these conditions, can be treated as verbatim copying in other +respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy a +computer-network location from which the general network-using public +has access to download using public-standard network protocols a +complete Transparent copy of the Document, free of added material. If +you use the latter option, you must take reasonably prudent steps, when +you begin distribution of Opaque copies in quantity, to ensure that this +Transparent copy will remain thus accessible at the stated location +until at least one year after the last time you distribute an Opaque +copy (directly or through your agents or retailers) of that edition to +the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. + +4. MODIFICATIONS +---------------- + +You may copy and distribute a Modified Version of the Document under the +conditions of sections 2 and 3 above, provided that you release the +Modified Version under precisely this License, with the Modified Version +filling the role of the Document, thus licensing distribution and +modification of the Modified Version to whoever possesses a copy of it. +In addition, you must do these things in the Modified Version: + +- A. Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions (which + should, if there were any, be listed in the History section of the + Document). You may use the same title as a previous version if the + original publisher of that version gives permission. +- B. List on the Title Page, as authors, one or more persons or + entities responsible for authorship of the modifications in the + Modified Version, together with at least five of the principal + authors of the Document (all of its principal authors, if it has + fewer than five), unless they release you from this requirement. +- C. State on the Title page the name of the publisher of the Modified + Version, as the publisher. +- D. Preserve all the copyright notices of the Document. +- E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +- F. Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below. +- G. Preserve in that license notice the full lists of Invariant + Sections and required Cover Texts given in the Document’s license + notice. +- H. Include an unaltered copy of this License. +- I. Preserve the section Entitled “History”, Preserve its Title, and + add to it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section Entitled “History” in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. +- J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise the + network locations given in the Document for previous versions it was + based on. These may be placed in the “History” section. You may omit + a network location for a work that was published at least four years + before the Document itself, or if the original publisher of the + version it refers to gives permission. +- K. For any section Entitled “Acknowledgements” or “Dedications”, + Preserve the Title of the section, and preserve in the section all + the substance and tone of each of the contributor acknowledgements + and/or dedications given therein. +- L. Preserve all the Invariant Sections of the Document, unaltered in + their text and in their titles. Section numbers or the equivalent are + not considered part of the section titles. +- M. Delete any section Entitled “Endorsements”. Such a section may not + be included in the Modified Version. +- N. Do not retitle any existing section to be Entitled “Endorsements” + or to conflict in title with any Invariant Section. +- O. Preserve any Warranty Disclaimers. + +If the Modified Version includes new front-matter sections or appendices +that qualify as Secondary Sections and contain no material copied from +the Document, you may at your option designate some or all of these +sections as invariant. To do this, add their titles to the list of +Invariant Sections in the Modified Version’s license notice. These +titles must be distinct from any other section titles. + +You may add a section Entitled “Endorsements”, provided it contains +nothing but endorsements of your Modified Version by various +parties—for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of Front-Cover +Text and one of Back-Cover Text may be added by (or through arrangements +made by) any one entity. If the Document already includes a cover text +for the same cover, previously added by you or by arrangement made by +the same entity you are acting on behalf of, you may not add another; +but you may replace the old one, on explicit permission from the +previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + +5. COMBINING DOCUMENTS +---------------------- + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its license +notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by adding +at the end of it, in parentheses, the name of the original author or +publisher of that section if known, or else a unique number. Make the +same adjustment to the section titles in the list of Invariant Sections +in the license notice of the combined work. + +In the combination, you must combine any sections Entitled “History” in +the various original documents, forming one section Entitled “History”; +likewise combine any sections Entitled “Acknowledgements”, and any +sections Entitled “Dedications”. You must delete all sections Entitled +“Endorsements”. + +6. COLLECTIONS OF DOCUMENTS +--------------------------- + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. + +7. AGGREGATION WITH INDEPENDENT WORKS +------------------------------------- + +A compilation of the Document or its derivatives with other separate and +independent documents or works, in or on a volume of a storage or +distribution medium, is called an “aggregate” if the copyright resulting +from the compilation is not used to limit the legal rights of the +compilation’s users beyond what the individual works permit. When the +Document is included in an aggregate, this License does not apply to the +other works in the aggregate which are not themselves derivative works +of the Document. + +If the Cover Text requirement of section 3 is applicable to these copies +of the Document, then if the Document is less than one half of the +entire aggregate, the Document’s Cover Texts may be placed on covers +that bracket the Document within the aggregate, or the electronic +equivalent of covers if the Document is in electronic form. Otherwise +they must appear on printed covers that bracket the whole aggregate. + +8. TRANSLATION +-------------- + +Translation is considered a kind of modification, so you may distribute +translations of the Document under the terms of section 4. Replacing +Invariant Sections with translations requires special permission from +their copyright holders, but you may include translations of some or all +Invariant Sections in addition to the original versions of these +Invariant Sections. You may include a translation of this License, and +all the license notices in the Document, and any Warranty Disclaimers, +provided that you also include the original English version of this +License and the original versions of those notices and disclaimers. In +case of a disagreement between the translation and the original version +of this License or a notice or disclaimer, the original version will +prevail. + +If a section in the Document is Entitled “Acknowledgements”, +“Dedications”, or “History”, the requirement (section 4) to Preserve its +Title (section 1) will typically require changing the actual title. + +9. TERMINATION +-------------- + +You may not copy, modify, sublicense, or distribute the Document except +as expressly provided under this License. Any attempt otherwise to copy, +modify, sublicense, or distribute it is void, and will automatically +terminate your rights under this License. + +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally terminates +your license, and (b) permanently, if the copyright holder fails to +notify you of the violation by some reasonable means prior to 60 days +after the cessation. + +Moreover, your license from a particular copyright holder is reinstated +permanently if the copyright holder notifies you of the violation by +some reasonable means, this is the first time you have received notice +of violation of this License (for any work) from that copyright holder, +and you cure the violation prior to 30 days after your receipt of the +notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, receipt of a copy of some or all of the same material does +not give you any rights to use it. + +10. FUTURE REVISIONS OF THIS LICENSE +------------------------------------ + +The Free Software Foundation may publish new, revised versions of the +GNU Free Documentation License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. See https://www.gnu.org/licenses/. + +Each version of the License is given a distinguishing version number. If +the Document specifies that a particular numbered version of this +License “or any later version” applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. If the Document specifies +that a proxy can decide which future versions of this License can be +used, that proxy’s public statement of acceptance of a version +permanently authorizes you to choose that version for the Document. + +11. RELICENSING +--------------- + +“Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World +Wide Web server that publishes copyrightable works and also provides +prominent facilities for anybody to edit those works. A public wiki that +anybody can edit is an example of such a server. A “Massive Multiauthor +Collaboration” (or “MMC”) contained in the site means any set of +copyrightable works thus published on the MMC site. + +“CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 +license published by Creative Commons Corporation, a not-for-profit +corporation with a principal place of business in San Francisco, +California, as well as future copyleft versions of that license +published by that same organization. + +“Incorporate” means to publish or republish a Document, in whole or in +part, as part of another Document. + +An MMC is “eligible for relicensing” if it is licensed under this +License, and if all works that were first published under this License +somewhere other than this MMC, and subsequently incorporated in whole or +in part into the MMC, (1) had no cover texts or invariant sections, and +(2) were thus incorporated prior to November 1, 2008. + +The operator of an MMC Site may republish an MMC contained in the site +under CC-BY-SA on the same site at any time before August 1, 2009, +provided the MMC is eligible for relicensing. + +ADDENDUM: How to use this License for your documents +---------------------------------------------------- + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and license +notices just after the title page: + +:: + + Copyright (C) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the “with … Texts.” line with this: + +:: + + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of free +software license, such as the GNU Affero General Public License, to permit +their use in free software. diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst @@ -0,0 +1,40 @@ +.. + This file is part of Frosix. + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + + @author Joel Urech + +Frosix Documentation +======================= + +At the moment, Frosix is an implementation in a very early state of the FROST threshold signature scheme published at the end of 2020 by Chelsea Komlo and Ian Goldberg [1]. + + +Documentation Overview +---------------------- + +.. toctree:: + :numbered: + :maxdepth: 2 + + introduction + libfrost + rest + sources + appendix + +.. toctree:: + :hidden: + + fdl-1.3 diff --git a/doc/sphinx/introduction.rst b/doc/sphinx/introduction.rst @@ -0,0 +1,71 @@ +.. + This file is part of Frosix. + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + + @author Joel Urech + +============ +Introduction +============ + +The documentation is not up-to-date and will be updated soon. + + +The Problem +^^^^^^^^^^^ + +Virtually our entire modern world is nowadays secured by digital signatures. + +Simply stated, a digital signature is a cryptographic proof of the originator of some digital data. +If anyone manipulates signed data or tries to impersonate someone else, this will be detected thanks to signatures. + +The trust model of signatures is only discussed here to the extent that a private key is required to generate a valid signature, and we assume that we are able to keep such a private key safe. +But this assumption is not correct, as we have to realize again and again! + +In Dezember 2022, Bruce Schneier, a well known cryptographer, stated the following after another incident became public: +"This is a huge problem. The whole system of authentication rests on the assumption that signing keys are kept secret by the legitimate signers. Once that assumption is broken, all bets are off:" [5] + + +Possible Solution +^^^^^^^^^^^^^^^^^ + +A possible solution to this problem could lie in the cryptographic field of ``Distributed Key Generation and Threshold Signatures``, which the author has chosen as topic for his Project2 and Bachelor Thesis. + +The basic idea behind this is simple: With a Threshold Signature Scheme, we can distribute the responsibility among many persons, services or systems. +And only if a fixed number (threshold) of those work together they can generate a valid signature. +This also means, that an attacker has to compromisse at least this threshold number of persons, services or systems to be able to generate a valid signature on his own. + +If we now use a Distributed Key Generation process to generate our key pair, the private key will never be materialized at any time! +In a Distributed Key Generation process, all participants contribute equally to the resulting key pair and no one knows more than exactly his own private key share. + +During the semester and while working on this topic, the working title Frosix (FROST Signatures) has evolved. + + +Frosix +^^^^^^ + +The goal of Frosix is to provide a safe and secure signature service, based on the FROST protocol by Chelsea Komlo and Ian Goldberg [1]. + +In the end, Frosix should include an implementation to run small web servers - the providers - which a software, running on a client, can access via a simple REST API. +The software on the client side will be a simple CLI as a first step. + +The providers are designed to only store the data necessary for its service, either encrypted without knowing the key, or just in form of a salted hash. +The drawback of this complete zero knowledge driven strategy is that the information which is needed to let a provider participate in a signing process, has again to be stored securly by the user. +Obviously this means that the attacking vector of such a provider is really small. But what happens if the secret data is stolen? + +For this reason there will be a further security mechanism in Frosix. +Just as with GNU Anastasis [3], Frosix providers are required to challenge, respectively authenticate their users. +This ensures that, depending on the challenge selected, only the legitimate user can have a valid signature generated. + +Additionally there are plans to integrate the payment system GNU Taler, so that providers do not have to offer this service for free. diff --git a/doc/sphinx/libfrost.rst b/doc/sphinx/libfrost.rst @@ -0,0 +1,142 @@ +.. + This file is part of Frosix. + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + + @author Joel Urech + +============================ +How to use Frosix's Libfrost +============================ + +The library libfrost is an implementation of the FROST protocol and does not reflect the latest design decisions of Frosix at the moment. +Additionally, the distributed key generation is generating correct key material, but needs a revision and a stricter typification. + + +Key Generation +============== + +Libfrost provides two possibilities to generate key pairs. + + +Trusted Dealer +^^^^^^^^^^^^^^ + +Trusted dealer should only be used for testing purposes! +With trusted dealer everything can be generated by itself and the need for several participants to generate keys is eliminated. +But also the main security property of the whole system is eliminated and can not be guaranteed. +The reason for this is the fact, that with trusted dealer the secret key exists for a short time. But that could be enough for a strong attacker to learn and therefore misuse the secret key. + +To let Libfrost create key pairs with trusted dealer, just call the function below and provide the number of key shares (num_of_participants) and the threshold value. + +``FROST_trusted_dealer_keygen (key_pairs[], num_of_participants, threshold)`` + + +Distributed Key Generation +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Round 1 +------- + +First every participant initializes an object of the struct FROST_DkgCommitment. +This will allocate some memory on the heap. The threshold value must be already known. + + ``FROST_initialize_dkg_commitment (dkg_commitment, my_index, threshold)`` + +Every participant does now makes a kind of a trusted dealer on his own and commits to each of the t-1 values of the created polynomial. +Additionally, every participant has to compute a zero knowledge proof of the underlying secret (y-value of the point x=0 on the polynomial). + +This function below does all of this and returns a commitment and a share for each participant. +The commitment should now be send to all other participants. But do not send the dkg shares! + + ``FROST_keygen_begin (*dkg_commitment, dkg_shares[], my_index, num_of_participants, threshold)`` + + +Round 2 +------- + +Before receiving the commitments, one should initialize further objects of type FROST_DkgCommitment. + +After receiving all commitments from all other participants, they have to be validated. +This means, that every value will be checked if it is a point on the curve25519 and correctly encoded. +Additionally the included zero knowledge proof will be validated as well. + +If any of the participants commitment or zero knowledge proof fails the validation, exclude this participant. + + ``FROST_keygen_receive_commitments_and_validate_peers (dkg_commitments[], num_of_participants)`` + + +Round 3 +------- + +Finally send to each participant his share and also receive from each participant a share. +This shares will be verified against the previously received commitments. +If this check failes, the distributed key generation process must be restarted without the failing participant. +But if all received shares are correct, this function computes the individual key pair and also derives the group public key from all commitments. + + ``FROST_keygen_finalize (*key_pair, my_index, shares[], commitments[], num_of_participants)`` + +In the end, every initialized struct should be properly freed. + + ``FROST_free_dkg_commitment (*dkg_commitment)`` + +Every participant now has a key share and can participate in a signing process. + + +Sign a message +============== + +Round 1 +^^^^^^^ + +The Signature Aggregator 'SA' chooses 't' (t = threshold) random participants out of all available participants and asks them to send him a commitment. + +Each chosen participant generates a nonce and a commitment and sends the commitment back to the 'SA'. +The nonce should be stored securely, we will use it in round 2. + + ``FROST_generate_nonce_and_commitment (nonce, commitment, my_key_pair)`` + + +Round 2 +^^^^^^^ + +To issue a signature over an arbitrary long message (msg with length msg_len), the message must first be converted to a point on the curve by the 'SA'. + + ``FROST_message_to_hash (message_hash, msg, msg_len)`` + +The 'SA' constructs then a sorted list out of all received commitments and send this list of commitments together with the message hash to each chosen participant. +Each chosen participant validates the data from the 'SA' and aborts if the validation failes. + + ``FROST_validate_message_hash_and_commitments (message_hash, commitments[], commitments_len))`` + + +If all data from the 'SA' are valid, every chosen participant computes a signature share and sends this signature share back to the 'SA'. + + ``FROST_sign_message_hash (signature_share, mesage_hash, commitments[], commitments_len, my_key_pair, my_nonce)`` + +The 'SA' receives and verifies each partial signature and aborts if the verification fails. + + ``FROST_verify_signature_share (commitment_i, signature_share_i, commitments[], commitments_len, public_key, message_hash)`` + +If all partial signatures are succesfully verified, the 'SA' finally creates the signature. + + ``FROST_compose_signature (signature, commitments[], signature_shares[], commitments_and_sig_shares_len, message_hash)`` + + +Verify +====== + +The verification of a given signature over a specific message is simple. Just call the function below with the public key, the signature and the hash of the message. +If the return value is 1, the signature is correct. + + ``FROST_verify_signature (public_key, signature, message_hash)`` diff --git a/doc/sphinx/rest.rst b/doc/sphinx/rest.rst @@ -0,0 +1,750 @@ +.. + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + + @author Christian Grothoff + @author Joel Urech + +======== +REST API +======== + +.. _config: + +----------------------- +Receiving Configuration +----------------------- + +.. http:get:: /config + + Obtain the configuration details of the provider. + +**Response:** + +Returns a `ProviderConfigurationResponse`_. + + +.. _ProviderConfigurationResponse: +.. ts:def:: ProviderConfigurationResponse + + interface ProviderConfigurationResponse { + + // Protocol identifier, clarifies that this is a Frosix provider. + name: "frosix"; + + // libtool-style representation of the Exchange protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". + version: string; + + // What is the name of this provider? + business_name: string; + + // Supported authorization methods. + methods: AuthorizationMethodConfig[]; + + // Payment required to create a key. + // Not yet implemented! + // key_creation_fee: Amount; + + // Salt value with 128 bits of entropy. + // Different providers will use different high-entropy salt values. + // The resulting **provider salt** is then used in various operations to ensure + // cryptographic operations differ by provider. + // A provider must never change its salt value. + provider_salt: string; + + // Public key of this provider. + public_key: string; + + } + +.. _AuthorizationMethodConfig: +.. ts:def:: AuthorizationMethodConfig + + interface AuthorizationMethodConfig { + // Name of the authorization method. + type: string; + + // Fee for issuing a signature share using this method. + // Not yet implemented! + // cost: Amount; + + } + + +.. _terms: + +-------------------------- +Receiving Terms of Service +-------------------------- + +.. http:get:: /terms + + Obtain the terms of service of the provider. + // Not yet implemented! + + +.. _seed: + +---- +Seed +---- + +.. http:get:: /seed + + Returns an high-entropy seed. Binary data in the HTTP body. + This API should be used every time the clients need high entropy. + The entropy returned MUST be mixed with locally generated entropy. + + +.. _key: + +-------------- +Key Generation +-------------- + + +Distributed Key Generation +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. http:post:: /dkg-commitment/$ID/ + + Let the provider compute a commitment for a polynomial with degree threshold-1. + ``$ID`` is the SHA-512 hash over the following data in Crockford base32 endoding: `ContextString`, `AuthHash`, `Identifier`, `NumOfParticipants`, `Threshold`, `PublicProviderSalt`, "FROSIX-DKG-ID". + + **Request:** + + Upload a `DkgCommitmentRequest`. + + **Response:** + + :http:statuscode:`201 Created`: + The provider responds with a `DkgCommitmentResponse`. + + **Details:** + + .. _DkgCommitmentRequest: + .. ts:def:: DkgCommitmentRequest + + interface DkgCommitmentRequest { + + // Unique identifier within the group. + provider_index: Identifier; + + // Minimum number of participants needed to sign a message. + threshold: Threshold; + + // ContextString is the main source of entropy to sample the commitments and should draw its entropy from several sources (e.g. with GET /seed from each participating provider). + context_string: ContextString; + + // Salted hash of authentication data, i.e. phone number, e-mail address, ... + // Or hash of the public key used to verify the secret answer of a security question. + auth_hash: AuthHash; + + // Public keys of all participating providers. + // Number of public key equals the total number of participants (n). + providers_public_keys: ProviderPublicKey[]; + + } + + .. _DkgCommitmentResponse: + .. ts:def:: DkgCommitmentResponse + + interface DkgCommitmentResponse { + + // Unique identifier within the group + provider_index: Identifier; + + // List of commitments, corresponding to the computed polynomial. + dkg_commitment: DkgCommitment[threshold]; + + // Zero Knowledge Proof of the corresponding secret of the computed polynomial. + zkp: DkgZkp; + + // Public Key to derive an symmetric key to encrypt the secret share intended for this provider (ECDHE). + provider_public_key: EphemeralPublicKey; + } + + .. _DkgZkp: + .. ts:def:: DkgZkp + + interface DkgZkp { + r: R; + z: z; + } + + +.. http:post:: /dkg-shares/$ID + + Upload the DKG commitments of all other participants and receive encrypted shares for all other participants. + ``$ID`` is the SHA-512 hash over the following data in Crockford base32 endoding: `ContextString`, `AuthHash`, `Identifier`, `NumOfParticipants`, `Threshold`, `PublicProviderSalt`, "FROSIX-DKG-ID". + + **Request:** + + Upload a `DkgSecretSharesRequest`_. + + **Response:** + + :http:statuscode:`201 Created`: + The provider responds with a `DkgSecretSharesResponse`_. + + **Details:** + + .. _DkgSecretSharesRequest: + .. ts:def:: DkgSecretSharesRequest: + + interface DkgSecretSharesRequest { + + // Identifier within the group. + provider_index: Identifier; + + // Minimum number of participants needed to sign a message. + threshold: Threshold; + + // Number of participants participating in the distributed key generation. + num_of_participants: NumOfParticipants; + + // ContextString is the source of entropy to recover commitments. + context_string: ContextString; + + // Salted hash of some challenge data, i.e. phone number, e-mail address, ... + // Or hash of the public key used to verify the secret answer of a security question. + auth_hash: AuthHash; + + // Public keys of all participating providers. + // Number of public key equals total number of participants (n). + providers_public_keys: ProviderPublicKey[]; + + // The commitments of all participants + dkg_commitments: DkgCommitmentResponse[num_of_participants - 1]; + + } + + .. _DkgSecretSharesResponse: + .. ts:def:: DkgSecretSharesResponse: + + interface DkgSecretSharesResponse { + + // The secret shares + secret_shares: DkgSecretShare[num_of_participants - 1]; + + } + + .. _DkgSecretShare: + .. ts:def:: DkgSecretShare: + + interface DkgSecretShare { + + // Identifier of the target participant + target: Identifier; + + // identifier of the issuer + issuer: Identifier; + + // Ephemeral key + ephemeral_key: EphemeralKey; + + enc_secret_share_data: [[ + + // The secret share - symmetric encrypted + secret_share: SecretShare; ]] + + } + + +.. http:post:: /dkg-key/$ID + + Upload all encrypted secret shares intended for this participant. + ``$ID`` is the SHA-512 hash over the following data in Crockford base32 endoding: `ContextString`, `AuthHash`, `Identifier`, `NumOfParticipants`, `Threshold`, `PublicProviderSalt`, "FROSIX-DKG-ID". + + **Request:** + + Upload a `KeyGenerateRequest`_. + + **Response:** + + :http:statuscode:`204 No Content`: + Key pair was successfully created and stored. + :http:statuscode:`404 Not Found`: + The provider does not know the provided ``$ID``. + :http:statuscode:`409 Conflict`: + The service already has a key pair stored under the resulting ``$ID`` (hash of resulting public key). + :http:statuscode:`402 Payment required`: + If the desired storage duration is longer than the default value in the terms of service of the provider, the provider must be paid additionally. + + **Details:** + + .. _KeyGenerateRequest: + .. ts:def:: KeyGenerateRequest: + + interface KeyGenerateRequest { + + // Identifier within the group. + provider_index: Identifier; + + // Minimum number of participants needed to sign a message. (needed to calculate secret polynomail) + threshold: Threshold; + + // ContextString is the source of entropy to recover the secret value behind the providers commitment. + context_string: ContextString; + + // Salted hash of some challenge data, i.e. phone number, e-mail address, ... + // Or hash of the public key used to verify the secret answer of a security question. + auth_hash: AuthHash; + + // Public keys of all participating providers. + // Number of public key equals total number of participants (n). + providers_public_keys: ProviderPublicKey[]; + + // For how many years from now would the client like us to store the truth? + expiration: Years; + + // All secret shares targeting this participant + secret_shares: DkgSecretShare[num_of_participants - 1]; + + } + + .. _KeyGenerateResponse: + .. ts:def:: KeyGenerateResponse: + + interface KeyGenerateResponse { + + // Public Key of created Distributed Secret Key + public_key: PublicKey + + // The signature is over the public key and the received authentication hash. + // This signature allows to verify the correctness of the authentication hash and to proof to a third person that this provider is involved in this signing group. + provider_signature: ProviderSignature + + } + + +.. _challenge: + +----------------- +Challenge Request +----------------- + +.. http:post:: /auth-request/$ID + + Let the provider create and send a challenge-code. + ``$ID`` is the SHA-512 hash over the following data in Crockford base32 endoding: `EncryptionKey`, `MessageHash`, "FROSIX-AUTH". + + **Request:** + + The request must be a `ChallengeCodeRequest`_. + + **Response:** + + :http:statuscode:`200 OK`: + The provider responds with an empty body. + :http:statuscode:`402 Payment Required`: + The provider requires payment to issue a challenge code. + + **Details:** + + .. _ChallengeCodeRequest: + .. ts:def:: ChallengeCodeRequest: + + interface ChallengeCodeRequest { + + // Encryption key + encryption_key: EncryptionKey; + + // Authentication method + auth_method: AuthMethod; + + // Authentication data + auth_data: AuthData; + + // Authentication nonce + auth_nonce: AuthNonce; + + // Hash of the message. + // The message is bound to the challenge code. A challenge code can therefore only be used for a specific message. + message_hash: MessageHash; + } + + +.. _sign: + +------- +Signing +------- + +.. http:post:: /sig-commitment/$ID + + A provider first authenticates an incoming request and then issues a commitment, which is bound to the submitted message. + ``$ID`` is the SHA-512 hash over the following data in Crockford base32 endoding: `EncryptionKeyHash`, `MessageHash`, "FROSIX-SIG". + + **Request:** + + The request must be a `SignatureCommitmentRequest`_. + + **Response:** + + :http:statuscode:`200 OK`: + The provider responds with a `SignatureCommitmentResponse`_. + :http:statuscode:`403 Forbidden`: + The client failed the authentication challenge. + :http:statuscode:`404 Not Found`: + The provider does not know the provided ``$ID``. + :http:statuscode:`404 Not found`: + The provider does not know the given ``$ID``. + :http:statuscode:`410 Gone`: + The challenge has expired. + :http:statuscode:`429 Too Many Requests`: + Too many attempts. + + **Details:** + + .. _SignatureCommitmentRequest: + .. ts:def:: SignatureCommitmentRequest: + + interface SigantureCommitmentRequest { + + // Hash of the encryption key, used to identify the corresponding entry in the database. + encryption_key_hash: EncryptionKeyHash; + + // Authentication method in order to authorize the incoming request. + auth_method: AuthMethod; + + // (Optional) If its a challenge code based authentication, authentication data contains the hash of the challenge code. + auth_data: AuthData; + + // (Optional) If its a security question, this authentication signature over the `MessageHash` is created with a private key which is derived from the secret answer. + auth_sig: AuthSig; + + // (Optional) Public key to verify the `AuthSig` signature. Gets hashed and compared to the hash stored in the provider's database. + auth_pub: AuthPub; + + // Hash of the message, serves as input for the key derivation function to sample a commitment. + message_hash: MessageHash; + + } + + .. _SignatureCommitmentResponse: + .. ts:def:: SignatureCommitmentResponse: + + interface SignatureCommitmentResponse { + + // First part of the commitment. + // Commitments are used to ensure, that every provider behaves well. + hiding_commitment: SigCommitment; + + // Second part of the commitment. + binding_commitment: SigCommitment; + + } + + +.. http:post:: /sig-share/$ID + + Ask the provider to compute a signature share. + ``$ID`` is the SHA-512 hash over the following data in Crockford base32 endoding: `EncryptionKeyHash`, `MessageHash`, "FROSIX-SIG". + + **Request:** + + Upload a `SignatureShareRequest`. + + **Response:** + + :http:statuscode:`200 OK`: + The provider responds with a `SignatureShareResponse`. + :http:statuscode:`404 Not found`: + The provider does not know the given ``$ID``. + + **Details:** + + .. _SignatureShareRequest: + .. ts:def:: SignatureShareRequest + + interface SignatureShareRequest { + + // Symmetric key to decrypt the key material + encryption_key: EncryptionKey; + + // Hash of the message + message_hash: MessageHash; + + // Sorted list of commitments of all participating providers. + // The own commitment has to be included. + commitments: SignatureCommitmentResponse[]; + + } + + .. _SignatureCommmitment: + .. ts:def:: SignatureCommitment + + interface SignatureCommitment { + + // Identifier + identifier: Identifier; + + // First part of the commitment. + // Commitments are used to ensure, that every provider behaves well. + hiding_commitment: SigCommitment; + + // Second part of the commitment. + binding_commitment: SigCommitment; + + } + + .. _SignatureShareResponse: + .. ts:def:: SignatureShareResponse + + interface SignatureShareResponse { + + // The resulting signature share + signature_share: SigShare; + + // The partial public key for convenience only - could be ommited + public_key_share: PublicKeyShare; + + } + + +.. _delete-key: + +---------- +Delete Key +---------- + +.. http:delete:: /dkg-key/$ID + + Deletes the key data if an entry is found with the ``$ID``. + ``$ID`` is the `EncryptionKeyHash`. + + **Response:** + + :http:statuscode:`200 OK`: + The provider responds with a `SignatureCommitmentResponse`_. + + +.. _encodings-ref: + +---------------- +Common encodings +---------------- + +This section describes how certain types of values are represented throughout the API. + +.. _base32: + +Binary Data +^^^^^^^^^^^ + +.. ts:def:: foobase + + type Base32 = string; + +Binary data is generally encoded using Crockford's variant of Base32 +(http://www.crockford.com/wrmg/base32.html), except that "U" is not excluded +but also decodes to "V" to make OCR easy. We will still simply use the JSON +type "base32" and the term "Crockford Base32" in the text to refer to the +resulting encoding. + + +Hash codes +^^^^^^^^^^ +Hash codes are strings representing base32 encoding of the respective +hashed data. See `base32`_. + +.. ts:def:: HashCode + + // 64-byte hash code. + type HashCode = string; + +.. ts:def:: SHA512HashCode + + type SHA512HashCode = HashCode; + +.. ts:def:: PublicProviderSalt + + type PublicProviderSalt: HashCode; + +.. ts:def:: ContextString + + // To generate a "good" ContextString, + // the client has to get fresh entropy from at least + // all participating providers (GET seed) and from itself. + type ContextString = SHA512HashCode; + +.. ts:def:: MessageHash + + // Hash of the message, which shall be signed. + type MessageHash = SHA512HashCode; + +.. ts:def:: EncryptionKey + + // The encryption key is used to encrypt and decrypt the key data stored in the provider's database. + type EncryptionKey = SHA512HashCode; + +.. ts:def:: EncryptionKeyHash + + // Hash of the encryption key. Used to identify the corresponding entry in the provider's database. + type EncryptionKeyHash = SHA512HashCode; + +.. ts:def:: AuthHash + + // The authentication hash is a salted hash of the authentication data which gets stored in the provider's database. + type AuthHash = SHA512HashCode; + +.. ts:def:: AuthNonce + + // Nonce used as salt to hash `AuthData` to receive `AuthHash`. + tpye AuthNonce = SHA512HashCode; + + +Curve25519 +^^^^^^^^^^ +32-byte values representig base32 encoding of either a point on Curve25519 or a scalar for operations on points on Curve 25519. + +.. ts:def:: Cs25519Point + + type Cs25519Point = string; + +.. ts:def:: Cs25519Scalar + + type Cs25519Scalar = string; + +.. ts:def:: SigCommitment + + type SigCommitment = Cs25519Point; + +.. ts:def:: DkgCommitment + + type DkgCommitment = Cs25519Point; + +.. ts:def:: SecretShare + + type SecretShare = Cs25519Scalar; + +.. ts:def:: EddsaPublicKey + + // EdDSA and ECDHE public keys always point on Curve25519 + // and represented using the standard 256 bits Ed25519 compact format, + // converted to Crockford `Base32`. + type EddsaPublicKey = string; + +.. ts:def:: EddsaPrivateKey + + // EdDSA and ECDHE public keys always point on Curve25519 + // and represented using the standard 256 bits Ed25519 compact format, + // converted to Crockford `Base32`. + type EddsaPrivateKey = string; + + +Signatures +^^^^^^^^^^ + +.. ts:def:: EddsaSignature + + // EdDSA signatures are transmitted as 64-bytes `base32` + // binary-encoded objects with just the R and S values (base32_ binary-only). + type EddsaSignature = string; + +.. ts:def:: R + + // The signature challenge. + type R = Cs25519Point; + +.. ts:def:: z + + // A single share of the resulting signature. + type z = Cs25519Scalar; + +.. ts:def:: ProviderSignature + + // Signature of a provider over the public key and the authentication data. + type ProviderSignature = EddsaSignature; + +.. ts:def:: AuthSig + + // Signature over the message with a private key derived from the secret answer. + type AuthSig = EddsaSignature; + + +Keys +^^^^ + +.. ts:def:: SecretKeyShare + + type SecretKeyShare = Cs25519Scalar; + +.. ts:def:: PublicKeyShare + + type PublicKeyShare = Cs25519Point; + +.. ts:def:: PublicKey + + type PublicKey = Cs25519Point; + +.. ts:def:: SigShare + + type SigShare = Cs25519Scalar; + +.. ts:def:: ProviderPublicKey + + type ProviderPublicKey = EddsaPublicKey; + +.. ts:def:: EphemeralPublicKey + + type EphemeralPublicKey = EddsaPublicKey; + +.. ts:def:: EphemeralKey + + type EphemeralKey = EddsaPublicKey; + +.. ts:def:: AuthPub + + type AuthPub = EddsaPublicKey; + +Integers +^^^^^^^^ + +.. ts:def:: UInt8 + + // JavaScript numbers restricted to the range of 0-255 + type UInt8 = number; + +.. ts:def:: Identifier + + // Identifier in the group + type Identifier = UInt8; + +.. ts:def:: Threshold + + type Threshold = UInt8; + +.. ts:def:: NumOfParticipants + + type NumOfParticipants = UInt8; + +.. ts:def:: Years + + type Years = number; + + +Strings +^^^^^^^ + +.. ts:def:: AuthMethod + + type AuthMethod = string; + +.. ts:def:: AuthData + + type AuthData = string; diff --git a/doc/sphinx/sources.rst b/doc/sphinx/sources.rst @@ -0,0 +1,32 @@ +.. + This file is part of Frosix. + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + + @author Joel Urech + +======= +Sources +======= + + [1] C. Komlo and I. Goldberg, "FROST: Flexible Round-Optimized Schnorr Threshold Signatures", https://eprint.iacr.org/2020/852.pdf + + [2] C. Komlo, I. Goldberg and C.A. Wood, "Two-Round Threshold Schnorr Signatures with FROST", https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-12.html + + [3] C. Grothoff, D. Meister and D. Neufeld "GNU Anastasis REST API", https://git.taler.net/anastasis.git/tree/doc/sphinx/rest.rst + + [4] libsodium, https://doc.libsodium.org/ + + [5] B. Schneier "Leaked Signing Keys Are Being Used to Sign Malware", https://www.schneier.com/blog/archives/2022/12/leaked-signing-keys-are-being-used-to-sign-malware.html + + [6] C. Komlo and I. Goldberg, "frost: An implementation in Rust", https://git.uwaterloo.ca/ckomlo/frost/ +\ No newline at end of file diff --git a/src/Makefile.am b/src/Makefile.am @@ -0,0 +1,3 @@ +# This Makefile is in the public domain + +SUBDIRS = include libfrostlow libfrosthigh libfrostdistkeygen libfrosttrusteddealer libfrostverify util frosixdb authorization backend restclient libfrosix cli . diff --git a/src/authorization/Makefile.am b/src/authorization/Makefile.am @@ -0,0 +1,49 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +cfgdir = $(prefix)/share/frosix/config.d/ + + +pkgcfgdir = $(prefix)/share/frosix/config.d/ +plugindir = $(libdir)/frosix +pkgdatadir= $(prefix)/share/frosix/ + +EXTRA_DIST = \ + $(pkgdata_DATA) \ + $(cfg_DATA) \ + $(bin_SCRIPTS) + + +lib_LTLIBRARIES = \ + libfrosixauthorization.la + +libfrosixauthorization_la_SOURCES = \ + frosix_authorization_plugin.c +libfrosixauthorization_la_LIBADD = \ + $(LTLIBINTL) +libfrosixauthorization_la_LDFLAGS = \ + -ltalerutil \ + -lgnunetutil \ + -lmicrohttpd \ + -lltdl \ + $(XLIB) + + +plugin_LTLIBRARIES = \ + libfrosix_plugin_authorization_file.la + + +libfrosix_plugin_authorization_file_la_SOURCES = \ + frosix_authorization_plugin_file.c +libfrosix_plugin_authorization_file_la_LIBADD = \ + $(LTLIBINTL) +libfrosix_plugin_authorization_file_la_LDFLAGS = \ + $(top_builddir)/src/frosixdb/libfrosixdb.la \ + -ltalerjson \ + -ltalermhd \ + -ltalerutil \ + -lgnunetjson \ + -lgnunetutil \ + -lmicrohttpd \ + -ljansson \ + $(XLIB) +\ No newline at end of file diff --git a/src/authorization/frosix_authorization_plugin.c b/src/authorization/frosix_authorization_plugin.c @@ -0,0 +1,227 @@ +/* + This file is part of Frosix + Copyright (C) 2015, 2016, 2021 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file frosix_authorization_plugin.c + * @brief Logic to load authorization plugin + * @author Christian Grothoff + * @author Dominik Meister + */ +#include "platform.h" +#include "frosix_authorization_lib.h" +#include <ltdl.h> + + +/** + * Head of linked list for all loaded plugins + */ +static struct AuthPlugin *ap_head; + +/** + * Tail ofinked list for all loaded plugins + */ +static struct AuthPlugin *ap_tail; + + +/** + * Authentication plugin which is used to verify code based authentication + * like SMS, E-Mail. + */ +struct AuthPlugin +{ + /** + * Kept in a DLL. + */ + struct AuthPlugin *next; + + /** + * Kept in a DLL. + */ + struct AuthPlugin *prev; + + /** + * Actual plugin handle. + */ + struct FROSIX_AuthorizationPlugin *authorization; + + /** + * I.e. "sms", "phone". + */ + char *name; + + /** + * Name of the shared object providing the plugin logic. + */ + char *lib_name; + + /** + * Authorization context passed to the plugin. + */ + struct FROSIX_AuthorizationContext ac; + +}; + + +struct FROSIX_AuthorizationPlugin * +FROSIX_authorization_plugin_load ( + const char *method, + struct FROSIX_DatabasePlugin *db, + const struct GNUNET_CONFIGURATION_Handle *FH_cfg) +{ + struct FROSIX_AuthorizationPlugin *authorization; + char *lib_name; + char *sec_name; + struct AuthPlugin *ap; + char *currency; + struct TALER_Amount cost; + + for (ap = ap_head; NULL != ap; ap = ap->next) + if (0 == strcmp (method, + ap->name)) + return ap->authorization; + if (GNUNET_OK != + TALER_config_get_currency (FH_cfg, + &currency)) + return NULL; + ap = GNUNET_new (struct AuthPlugin); + ap->ac.db = db; + ap->ac.cfg = FH_cfg; + GNUNET_asprintf (&sec_name, + "authorization-%s", + method); + if (GNUNET_OK != + TALER_config_get_amount (FH_cfg, + sec_name, + "COST", + &cost)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + sec_name, + "COST"); + GNUNET_free (sec_name); + GNUNET_free (currency); + GNUNET_free (ap); + return NULL; + } + + GNUNET_free (currency); + GNUNET_free (sec_name); + GNUNET_asprintf (&lib_name, + "libfrosix_plugin_authorization_%s", + method); + authorization = GNUNET_PLUGIN_load (lib_name, + &ap->ac); + if (NULL == authorization) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Authentication method `%s' not supported\n", + method); + GNUNET_free (lib_name); + GNUNET_free (ap); + return NULL; + } + authorization->cost = cost; + ap->name = GNUNET_strdup (method); + ap->lib_name = lib_name; + ap->authorization = authorization; + GNUNET_CONTAINER_DLL_insert (ap_head, + ap_tail, + ap); + return authorization; +} + + +void +FROSIX_authorization_plugin_shutdown (void) +{ + struct AuthPlugin *ap; + + while (NULL != (ap = ap_head)) + { + GNUNET_CONTAINER_DLL_remove (ap_head, + ap_tail, + ap); + GNUNET_PLUGIN_unload (ap->lib_name, + ap->authorization); + GNUNET_free (ap->lib_name); + GNUNET_free (ap->name); + GNUNET_free (ap); + } +} + + +/** + * Libtool search path before we started. + */ +static char *old_dlsearchpath; + + +/** + * Setup libtool paths. + */ +void __attribute__ ((constructor)) +frosix_authorization_plugin_init (void) +{ + int err; + const char *opath; + char *path; + char *cpath; + + err = lt_dlinit (); + if (err > 0) + { + fprintf (stderr, + ("Initialization of plugin mechanism failed: %s!\n"), + lt_dlerror ()); + return; + } + opath = lt_dlgetsearchpath (); + if (NULL != opath) + old_dlsearchpath = GNUNET_strdup (opath); + path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR); + if (NULL != path) + { + if (NULL != opath) + { + GNUNET_asprintf (&cpath, "%s:%s", opath, path); + lt_dlsetsearchpath (cpath); + GNUNET_free (path); + GNUNET_free (cpath); + } + else + { + lt_dlsetsearchpath (path); + GNUNET_free (path); + } + } +} + + +/** + * Shutdown libtool. + */ +void __attribute__ ((destructor)) +frosix_authorization_plugin_fini (void) +{ + lt_dlsetsearchpath (old_dlsearchpath); + if (NULL != old_dlsearchpath) + { + GNUNET_free (old_dlsearchpath); + } + lt_dlexit (); +} + + +/* end of frosix_authorization_plugin.c */ diff --git a/src/authorization/frosix_authorization_plugin_file.c b/src/authorization/frosix_authorization_plugin_file.c @@ -0,0 +1,326 @@ +/* + This file is part of Frosix + Copyright (C) 2019 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file frosix_authorization_plugin_file.c + * @brief authorization plugin file based for testing + * @author Dominik Meister + */ +#include "platform.h" +#include "frosix_authorization_plugin.h" +#include <taler/taler_mhd_lib.h> +#include <gnunet/gnunet_db_lib.h> +#include "frosix_database_lib.h" +#include "frosix.h" + +/** + * How many retries do we allow per code? + */ +#define INITIAL_RETRY_COUNTER 3 + + +/** + * Saves the state of a authorization process + */ +struct FROSIX_AUTHORIZATION_State +{ + /** + * UUID of the challenge which is authorised + */ + struct FROSIX_ChallengeIdP truth_uuid; + + /** + * Code which is sent to the user (here saved into a file) + */ + uint64_t code; + + /** + * holds the truth information + */ + char *filename; + + /** + * closure + */ + void *cls; +}; + + +/** + * Validate @a data is a well-formed input into the challenge method, + * i.e. @a data is a well-formed phone number for sending an SMS, or + * a well-formed e-mail address for sending an e-mail. Not expected to + * check that the phone number or e-mail account actually exists. + * + * To be possibly used before issuing a 402 payment required to the client. + * + * @param cls closure with a `const struct ANASTASIS_AuthorizationContext *` + * @param connection HTTP client request (for queuing response) + * @param truth_mime mime type of @e data + * @param data input to validate (i.e. is it a valid phone number, etc.) + * @param data_length number of bytes in @a data + * @return #GNUNET_OK if @a data is valid, + * #GNUNET_NO if @a data is invalid and a reply was successfully queued on @a connection + * #GNUNET_SYSERR if @a data invalid but we failed to queue a reply on @a connection + */ +static enum GNUNET_GenericReturnValue +file_validate (void *cls, + struct MHD_Connection *connection, + const char *truth_mime, + const char *data, + size_t data_length) +{ + char *filename; + bool flag; + + (void) cls; + if (NULL == data) + return GNUNET_SYSERR; + filename = GNUNET_STRINGS_data_to_string_alloc (data, + data_length); + flag = false; + for (size_t i = 0; i<strlen (filename); i++) + { + if ( (filename[i] == ' ') || + (filename[i] == '/') ) + { + flag = true; + break; + } + } + if (flag) + return GNUNET_SYSERR; + GNUNET_free (filename); + return GNUNET_OK; +} + + +/** + * Begin issuing authentication challenge to user based on @a data. + * I.e. start to send SMS or e-mail or launch video identification. + * + * @param cls closure + * @param trigger function to call when we made progress + * @param trigger_cls closure for @a trigger + * @param truth_uuid Identifier of the challenge, to be (if possible) included in the + * interaction with the user + * @param code secret code that the user has to provide back to satisfy the challenge in + * the main anastasis protocol + * @param data input to validate (i.e. is it a valid phone number, etc.) + * @param data_length number of bytes in @a data + * @return state to track progress on the authorization operation, NULL on failure + */ +static struct FROSIX_AUTHORIZATION_State * +file_start (void *cls, + GNUNET_SCHEDULER_TaskCallback trigger, + void *trigger_cls, + const struct FROSIX_ChallengeIdP *truth_uuid, + uint64_t code, + const void *data, + size_t data_length) +{ + // const struct FROSIX_AuthorizationContext *ac = cls; + struct FROSIX_AUTHORIZATION_State *as; + // enum GNUNET_DB_QueryStatus qs; + /* If the user can show this challenge code, this + plugin is already happy (no additional + requirements), so mark this challenge as + already satisfied from the start. */ + /*qs = ac->db->mark_challenge_code_satisfied (ac->db->cls, + truth_uuid, + code); + if (qs <= 0) + { + GNUNET_break (0); + return NULL; + }*/ + as = GNUNET_new (struct FROSIX_AUTHORIZATION_State); + as->cls = cls; + as->truth_uuid = *truth_uuid; + as->code = code; + as->filename = GNUNET_strndup (data, + data_length); + return as; +} + + +/** + * Begin issuing authentication challenge to user based on @a data. + * I.e. start to send SMS or e-mail or launch video identification. + * + * @param as authorization state + * @param connection HTTP client request (for queuing response, such as redirection to video portal) + * @return state of the request + */ +static enum FROSIX_AUTHORIZATION_ChallengeResult +file_challenge (struct FROSIX_AUTHORIZATION_State *as, + struct MHD_Connection *connection) +{ + const char *mime; + const char *lang; + + mime = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_ACCEPT); + if (NULL == mime) + mime = "text/plain"; + lang = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_ACCEPT_LANGUAGE); + if (NULL == lang) + lang = "en"; + { + FILE *f = fopen (as->filename, "w"); + + if (NULL == f) + { + struct MHD_Response *resp; + MHD_RESULT mres; + + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, + "open", + as->filename); + resp = TALER_MHD_make_error (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "open"); + mres = MHD_queue_response (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + resp); + MHD_destroy_response (resp); + if (MHD_YES != mres) + return FROSIX_AUTHORIZATION_CRES_FAILED_REPLY_FAILED; + return FROSIX_AUTHORIZATION_CRES_FAILED; + } + + /* print challenge code to file */ + if (0 >= fprintf (f, + "%lu", + as->code)) + { + struct MHD_Response *resp; + MHD_RESULT mres; + + GNUNET_break (0 == fclose (f)); + resp = TALER_MHD_make_error (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "write"); + mres = MHD_queue_response (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + resp); + MHD_destroy_response (resp); + if (MHD_YES != mres) + return FROSIX_AUTHORIZATION_CRES_FAILED_REPLY_FAILED; + return FROSIX_AUTHORIZATION_CRES_FAILED; + } + GNUNET_break (0 == fclose (f)); + } + + /* Build HTTP response */ + { + struct MHD_Response *resp; + + if (TALER_MHD_xmime_matches (mime, + "application/json")) + { + resp = TALER_MHD_MAKE_JSON_PACK ( + GNUNET_JSON_pack_string ("challenge_type", + "FILE_WRITTEN"), + GNUNET_JSON_pack_string ("filename", + as->filename)); + } + else + { + size_t response_size; + char *response; + + response_size = GNUNET_asprintf (&response, + ("Challenge written to file")); + resp = MHD_create_response_from_buffer (response_size, + response, + MHD_RESPMEM_MUST_COPY); + GNUNET_free (response); + TALER_MHD_add_global_headers (resp); + GNUNET_break (MHD_YES == + MHD_add_response_header (resp, + MHD_HTTP_HEADER_CONTENT_TYPE, + "text/plain")); + } + + { + MHD_RESULT mres; + + mres = MHD_queue_response (connection, + MHD_HTTP_OK, + resp); + MHD_destroy_response (resp); + if (MHD_YES != mres) + return FROSIX_AUTHORIZATION_CRES_SUCCESS_REPLY_FAILED; + return FROSIX_AUTHORIZATION_CRES_SUCCESS; + } + } +} + + +/** + * Free internal state associated with @a as. + * + * @param as state to clean up + */ +static void +file_cleanup (struct FROSIX_AUTHORIZATION_State *as) +{ + GNUNET_free (as->filename); + GNUNET_free (as); +} + + +/** + * Initialize File based authorization plugin + * + * @param cls a configuration instance + * @return NULL on error, otherwise a `struct FROSIX_AuthorizationPlugin` + */ +void * +libfrosix_plugin_authorization_file_init (void *cls) +{ + const struct FROSIX_AuthorizationContext *ac = cls; + struct FROSIX_AuthorizationPlugin *plugin; + + plugin = GNUNET_new (struct FROSIX_AuthorizationPlugin); + plugin->cls = (void *) ac; + plugin->retry_counter = INITIAL_RETRY_COUNTER; + plugin->code_validity_period = GNUNET_TIME_UNIT_MINUTES; + plugin->code_rotation_period = GNUNET_TIME_UNIT_MINUTES; + plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_MINUTES; + plugin->validate = &file_validate; + plugin->start = &file_start; + plugin->challenge = &file_challenge; + plugin->cleanup = &file_cleanup; + return plugin; +} + + +/** + * Unload authorization plugin + * + * @param cls a `struct FROSIX_AuthorizationPlugin` + * @return NULL (always) + */ +void * +libfrosix_plugin_authorization_file_done (void *cls) +{ + struct FROSIX_AuthorizationPlugin *plugin = cls; + + GNUNET_free (plugin); + return NULL; +} diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am @@ -0,0 +1,51 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +pkgcfgdir = $(prefix)/share/frosix/config.d/ + +pkgcfg_DATA = \ + frosix.conf + +bin_PROGRAMS = \ + frosix-httpd + +frosix_httpd_SOURCES = \ + frosix-httpd.c frosix-httpd.h \ + frosix-httpd_mhd.c frosix-httpd_mhd.h \ + frosix-httpd_terms.c frosix-httpd_terms.h \ + frosix-httpd_config.c frosix-httpd_config.h \ + frosix-httpd_seed.c frosix-httpd_seed.h \ + frosix-httpd_dkg.h \ + frosix-httpd_common.c \ + frosix-httpd_dkg-commitment.c \ + frosix-httpd_dkg-shares.c \ + frosix-httpd_dkg-key.c \ + frosix-httpd_auth-challenge.c frosix-httpd_auth.h \ + frosix-httpd_sig.h \ + frosix-httpd_sig-commitment.c \ + frosix-httpd_sig-share.c \ + frosix-httpd_dkg-key_delete.c + +frosix_httpd_LDADD = \ + $(top_builddir)/src/authorization/libfrosixauthorization.la \ + $(top_builddir)/src/frosixdb/libfrosixdb.la \ + $(top_builddir)/src/util/libfrosixutil.la \ + $(top_builddir)/src/libfrostdistkeygen/libfrostdistkeygen.la \ + $(top_builddir)/src/libfrostverify/libfrostverify.la \ + $(top_builddir)/src/libfrosthigh/libfrosthigh.la \ + $(top_builddir)/src/libfrostlow/libfrostlow.la \ + -ljansson \ + -ltalermerchant \ + -ltalermhd \ + -ltalerjson \ + -ltalerutil \ + -lgnunetcurl \ + -lgnunetrest \ + -lgnunetjson \ + -lgnunetutil \ + -lmicrohttpd \ + -lsodium \ + $(XLIB) + +EXTRA_DIST = \ + $(pkgcfg_DATA) diff --git a/src/backend/frosix-httpd.c b/src/backend/frosix-httpd.c @@ -0,0 +1,1196 @@ +/* + This file is part of Frosix + (C) 2020-2022 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd.c + * @brief HTTP serving layer intended to provide basic backup operations + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + * @author Joel Urech + */ +#include "platform.h" +#include "frosix-httpd.h" +#include "frosix-httpd_mhd.h" +#include "frosix-httpd_terms.h" +#include "frosix-httpd_config.h" +#include "frosix-httpd_seed.h" +#include "frosix-httpd_dkg.h" +#include "frosix-httpd_sig.h" +#include "frosix-httpd_auth.h" +#include "frosix_database_lib.h" +#include "frosix_util_lib.h" +#include "gnunet/gnunet_curl_lib.h" +#include "taler/taler_util.h" + + +/** + * Annual fee for the backup account. + */ +struct TALER_Amount FH_annual_fee; + +/** + * Fee for a truth upload. + */ +struct TALER_Amount FH_signature_creation_fee; + +/** + * Amount of insurance. + */ +struct TALER_Amount FH_insurance; + +/** + * Cost for secure question truth download. + */ +struct TALER_Amount FH_question_cost; + +/** + * Our configuration. + */ +const struct GNUNET_CONFIGURATION_Handle *FH_cfg; + +/** + * Our Taler backend to process payments. + */ +char *FH_backend_url; + +/** + * Our fulfillment URL. + */ +char *FH_fulfillment_url; + +/** + * Our business name. + */ +char *FH_business_name; + +/** + * Our provider salt. + */ +struct FROSIX_ProviderSaltP FH_provider_salt; + +/** + * Our secret provider salt +*/ +struct FROSIX_SecretProviderSaltP FH_secret_provider_salt; + +/** + * FIXME +*/ +struct GNUNET_CRYPTO_EddsaPrivateKey FH_priv_sig_key; + +/** + * FIXME +*/ +struct GNUNET_CRYPTO_EddsaPublicKey FH_pub_sig_key; + +/** + * Number of policy uploads permitted per annual fee payment. + */ +unsigned long long FH_post_counter = 64LLU; + +/** + * Our context for making HTTP requests. + */ +struct GNUNET_CURL_Context *FH_ctx; + +/** + * Should a "Connection: close" header be added to each HTTP response? + */ +static int FH_connection_close; + +/** + * Task running the HTTP server. + */ +static struct GNUNET_SCHEDULER_Task *mhd_task; + +/** + * Heap for processing timeouts of requests. + */ +struct GNUNET_CONTAINER_Heap *FH_to_heap; + +/** + * Global return code + */ +static int global_result; + +/** + * The MHD Daemon + */ +static struct MHD_Daemon *mhd; + +/** + * Connection handle to the our database + */ +struct FROSIX_DatabasePlugin *db; + +/** + * Reschedule context for #FH_ctx. + */ +static struct GNUNET_CURL_RescheduleContext *rc; + +/** + * Set if we should immediately MHD_run() again. + */ +static int triggered; + +/** + * Username and password to use for client authentication + * (optional). + */ +static char *userpass; + +/** + * Type of the client's TLS certificate (optional). + */ +static char *certtype; + +/** + * File with the client's TLS certificate (optional). + */ +static char *certfile; + +/** + * File with the client's TLS private key (optional). + */ +static char *keyfile; + +/** + * This value goes in the Authorization:-header. + */ +static char *apikey; + +/** + * Passphrase to decrypt client's TLS private key file (optional). + */ +static char *keypass; + + +/** + * Function that queries MHD's select sets and + * starts the task waiting for them. + */ +static struct GNUNET_SCHEDULER_Task * +prepare_daemon (void); + + +/** + * Call MHD to process pending requests and then go back + * and schedule the next run. + * + * @param cls the `struct MHD_Daemon` of the HTTP server to run + */ +static void +run_daemon (void *cls) +{ + (void) cls; + mhd_task = NULL; + do { + triggered = 0; + GNUNET_assert (MHD_YES == MHD_run (mhd)); + } while (0 != triggered); + mhd_task = prepare_daemon (); +} + + +/** + * Kick MHD to run now, to be called after MHD_resume_connection(). + * Basically, we need to explicitly resume MHD's event loop whenever + * we made progress serving a request. This function re-schedules + * the task processing MHD's activities to run immediately. + * + * @param cls NULL + */ +void +FH_trigger_daemon (void *cls) +{ + (void) cls; + if (NULL != mhd_task) + { + GNUNET_SCHEDULER_cancel (mhd_task); + mhd_task = GNUNET_SCHEDULER_add_now (&run_daemon, + NULL); + } + else + { + triggered = 1; + } +} + + +/** + * Kick GNUnet Curl scheduler to begin curl interactions. + */ +void +FH_trigger_curl (void) +{ + GNUNET_CURL_gnunet_scheduler_reschedule (&rc); +} + + +/** + * A client has requested the given url using the given method + * (MHD_HTTP_METHOD_GET, MHD_HTTP_METHOD_PUT, + * MHD_HTTP_METHOD_DELETE, MHD_HTTP_METHOD_POST, etc). The callback + * must call MHD callbacks to provide content to give back to the + * client and return an HTTP status code (i.e. MHD_HTTP_OK, + * MHD_HTTP_NOT_FOUND, etc.). + * + * @param cls argument given together with the function + * pointer when the handler was registered with MHD + * @param connection MHD connection handle with further request details + * @param url the requested url + * @param method the HTTP method used (MHD_HTTP_METHOD_GET, + * MHD_HTTP_METHOD_PUT, etc.) + * @param version the HTTP version string (i.e. + * MHD_HTTP_VERSION_1_1) + * @param upload_data the data being uploaded (excluding HEADERS, + * for a POST that fits into memory and that is encoded + * with a supported encoding, the POST data will NOT be + * given in upload_data and is instead available as + * part of MHD_get_connection_values(); very large POST + * data *will* be made available incrementally in + * @a upload_data) + * @param upload_data_size set initially to the size of the + * @a upload_data provided; the method must update this + * value to the number of bytes NOT processed; + * @param con_cls pointer that the callback can set to some + * address and that will be preserved by MHD for future + * calls for this request; since the access handler may + * be called many times (i.e., for a PUT/POST operation + * with plenty of upload data) this allows the application + * to easily associate some request-specific state. + * If necessary, this state can be cleaned up in the + * global MHD_RequestCompletedCallback (which + * can be set with the MHD_OPTION_NOTIFY_COMPLETED). + * Initially, `*con_cls` will be NULL. + * @return #MHD_YES if the connection was handled successfully, + * #MHD_NO if the socket must be closed due to a serious + * error while handling the request + */ +static MHD_RESULT +url_handler (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, + void **con_cls) +{ + static struct FH_RequestHandler handlers[] = { + /* Landing page, tell humans to go away. */ + { "/", MHD_HTTP_METHOD_GET, "text/plain", + "Hello, I'm Frosix. This HTTP server is not for humans.\n", 0, + &TMH_MHD_handler_static_response, MHD_HTTP_OK }, + { "/agpl", MHD_HTTP_METHOD_GET, "text/plain", + NULL, 0, + &TMH_MHD_handler_agpl_redirect, MHD_HTTP_FOUND }, + { "/terms", MHD_HTTP_METHOD_GET, NULL, + NULL, 0, + &FH_handler_privacy, MHD_HTTP_OK }, + { "/privacy", MHD_HTTP_METHOD_GET, NULL, + NULL, 0, + &FH_handler_terms, MHD_HTTP_OK }, + { "/config", MHD_HTTP_METHOD_GET, "text/json", + NULL, 0, + &FH_handler_config, MHD_HTTP_OK }, + { "/seed", MHD_HTTP_METHOD_GET, "arraybuffer", + NULL, 0, + &FH_seed_get, MHD_HTTP_OK }, + {NULL, NULL, NULL, NULL, 0, 0 } + }; + static struct FH_RequestHandler h404 = { + "", NULL, "text/html", + "<html><title>404: not found</title></html>", 0, + &TMH_MHD_handler_static_response, MHD_HTTP_NOT_FOUND + }; + static struct FH_RequestHandler h405 = { + "", NULL, "text/html", + "<html><title>405: method not allowed</title></html>", 0, + &TMH_MHD_handler_static_response, MHD_HTTP_METHOD_NOT_ALLOWED + }; + struct TM_HandlerContext *hc = *con_cls; + const char *correlation_id = NULL; + bool path_matched; + + if (NULL == hc) + { + struct GNUNET_AsyncScopeId aid; + + GNUNET_async_scope_fresh (&aid); + /* We only read the correlation ID on the first callback for every client */ + correlation_id = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + "Frosix-Correlation-Id"); + if ((NULL != correlation_id) && + (GNUNET_YES != GNUNET_CURL_is_valid_scope_id (correlation_id))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid incoming correlation ID\n"); + correlation_id = NULL; + } + hc = GNUNET_new (struct TM_HandlerContext); + *con_cls = hc; + hc->async_scope_id = aid; + hc->url = url; + } + if (0 == strcasecmp (method, + MHD_HTTP_METHOD_HEAD)) + method = MHD_HTTP_METHOD_GET; /* MHD will throw away the body */ + + GNUNET_SCHEDULER_begin_async_scope (&hc->async_scope_id); + if (NULL != correlation_id) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Handling request for (%s) URL '%s', correlation_id=%s\n", + method, + url, + correlation_id); + else + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Handling request (%s) for URL '%s'\n", + method, + url); + + /* POST /dkg-commitment/ID */ + if (0 == strncmp (url, + "/dkg-commitment/", + strlen ("/dkg-commitment/"))) + { + // we only accept post for this endpoint + if (0 != strcmp (method, MHD_HTTP_METHOD_POST)) + { + return TMH_MHD_handler_static_response (&h405, + connection); + } + + // get ID + struct FROSIX_DkgRequestIdP id; + const char *pub_key_str; + size_t len; + + pub_key_str = &url[strlen ("/dkg-commitment/")]; + len = strlen (pub_key_str); + + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data ( + pub_key_str, + len, + &id, + sizeof (id))) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "ID"); + } + + return FH_handler_dkg_commitment_post (connection, + hc, + &id, + &FH_provider_salt, + &FH_secret_provider_salt, + &FH_priv_sig_key, + &FH_pub_sig_key, + upload_data, + upload_data_size); + } + + /* POST /dkg-shares/ID */ + if (0 == strncmp (url, + "/dkg-shares/", + strlen ("/dkg-shares/"))) + { + // we only accept post for this endpoint + if (0 != strcmp (method, MHD_HTTP_METHOD_POST)) + { + return TMH_MHD_handler_static_response (&h405, + connection); + } + + // get ID + struct FROSIX_DkgRequestIdP id; + const char *pub_key_str; + size_t len; + + pub_key_str = &url[strlen ("/dkg-shares/")]; + len = strlen (pub_key_str); + + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data ( + pub_key_str, + len, + &id, + sizeof (id))) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "ID"); + } + + return FH_handler_dkg_shares_post (connection, + hc, + &id, + &FH_provider_salt, + &FH_secret_provider_salt, + upload_data, + upload_data_size); + } + + /* POST /dkg-key/ID */ + if (0 == strncmp (url, + "/dkg-key/", + strlen ("/dkg-key/"))) + { + // we only accept post and delete for this endpoint + if (0 != strcmp (method, MHD_HTTP_METHOD_POST) && + 0 != strcmp (method, MHD_HTTP_METHOD_DELETE)) + { + return TMH_MHD_handler_static_response (&h405, + connection); + } + + // get ID + struct FROSIX_DkgRequestIdP id; + const char *pub_key_str; + size_t len; + + pub_key_str = &url[strlen ("/dkg-key/")]; + len = strlen (pub_key_str); + + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data ( + pub_key_str, + len, + &id, + sizeof (id))) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "ID"); + } + + if (0 == strcmp (method, MHD_HTTP_METHOD_POST)) + { + /* create new key */ + return FH_handler_dkg_key_post (connection, + hc, + &id, + &FH_provider_salt, + &FH_secret_provider_salt, + &FH_priv_sig_key, + upload_data, + upload_data_size); + } + else + { + /* delete existing key */ + return FH_handler_key_delete (connection, + hc, + &id); + } + } + + /* POST /auth-challenge/ID */ + if (0 == strncmp (url, + "/auth-challenge/", + strlen ("/auth-challenge/"))) + { + // we only accept post for this endpoint + if (0 != strcmp (method, MHD_HTTP_METHOD_POST)) + { + return TMH_MHD_handler_static_response (&h405, + connection); + } + + // get ID + struct FROSIX_ChallengeRequestIdP id; + const char *pub_key_str; + size_t len; + + pub_key_str = &url[strlen ("/auth-challenge/")]; + len = strlen (pub_key_str); + + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data ( + pub_key_str, + len, + &id, + sizeof (id))) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "ID"); + } + + return FH_handler_auth_challenge_post (connection, + hc, + &id, + upload_data, + upload_data_size); + } + + /* POST /sig-commitment/ID */ + if (0 == strncmp (url, + "/sig-commitment/", + strlen ("/sig-commitment/"))) + { + // we only accept post for this endpoint + if (0 != strcmp (method, MHD_HTTP_METHOD_POST)) + { + return TMH_MHD_handler_static_response (&h405, + connection); + } + + // get ID + struct FROSIX_SigRequestIdP id; + const char *pub_key_str; + size_t len; + + pub_key_str = &url[strlen ("/sig-commitment/")]; + len = strlen (pub_key_str); + + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data ( + pub_key_str, + len, + &id, + sizeof (id))) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "ID"); + } + + return FH_handler_sig_commitment_post (connection, + hc, + &id, + upload_data, + upload_data_size); + } + + /* POST /sig-share/ID */ + if (0 == strncmp (url, + "/sig-share/", + strlen ("/sig-share/"))) + { + // we only accept post for this endpoint + if (0 != strcmp (method, MHD_HTTP_METHOD_POST)) + { + return TMH_MHD_handler_static_response (&h405, + connection); + } + + // get ID + struct FROSIX_SigRequestIdP id; + const char *pub_key_str; + size_t len; + + pub_key_str = &url[strlen ("/sig-share/")]; + len = strlen (pub_key_str); + + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data ( + pub_key_str, + len, + &id, + sizeof (id))) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "ID"); + } + + return FH_handler_sig_share_post (connection, + hc, + &id, + upload_data, + upload_data_size); + } + + path_matched = false; + for (unsigned int i = 0; NULL != handlers[i].url; i++) + { + struct FH_RequestHandler *rh = &handlers[i]; + + if (0 == strcmp (url, + rh->url)) + { + path_matched = true; + if (0 == strcasecmp (method, + MHD_HTTP_METHOD_OPTIONS)) + { + return TALER_MHD_reply_cors_preflight (connection); + } + if ( (NULL == rh->method) || + (0 == strcasecmp (method, + rh->method)) ) + { + return rh->handler (rh, + connection); + } + } + } + if (path_matched) + return TMH_MHD_handler_static_response (&h405, + connection); + return TMH_MHD_handler_static_response (&h404, + connection); +} + + +/** + * Shutdown task (magically invoked when the application is being + * quit) + * + * @param cls NULL + */ +static void +do_shutdown (void *cls) +{ + (void) cls; + // FIXME + // AH_resume_all_bc (); + // AH_truth_challenge_shutdown (); + // AH_truth_solve_shutdown (); + // AH_truth_upload_shutdown (); + if (NULL != mhd_task) + { + GNUNET_SCHEDULER_cancel (mhd_task); + mhd_task = NULL; + } + if (NULL != FH_ctx) + { + GNUNET_CURL_fini (FH_ctx); + FH_ctx = NULL; + } + if (NULL != rc) + { + GNUNET_CURL_gnunet_rc_destroy (rc); + rc = NULL; + } + if (NULL != mhd) + { + MHD_stop_daemon (mhd); + mhd = NULL; + } + if (NULL != db) + { + FROSIX_DB_plugin_unload (db); + db = NULL; + } + if (NULL != FH_to_heap) + { + GNUNET_CONTAINER_heap_destroy (FH_to_heap); + FH_to_heap = NULL; + } +} + + +/** + * Function called whenever MHD is done with a request. If the + * request was a POST, we may have stored a `struct Buffer *` in the + * @a con_cls that might still need to be cleaned up. Call the + * respective function to free the memory. + * + * @param cls client-defined closure + * @param connection connection handle + * @param con_cls value as set by the last call to + * the #MHD_AccessHandlerCallback + * @param toe reason for request termination + * @see #MHD_OPTION_NOTIFY_COMPLETED + * @ingroup request + */ +static void +handle_mhd_completion_callback (void *cls, + struct MHD_Connection *connection, + void **con_cls, + enum MHD_RequestTerminationCode toe) +{ + struct TM_HandlerContext *hc = *con_cls; + struct GNUNET_AsyncScopeSave old_scope; + + (void) cls; + (void) connection; + if (NULL == hc) + return; + GNUNET_async_scope_enter (&hc->async_scope_id, + &old_scope); + { +#if MHD_VERSION >= 0x00097304 + const union MHD_ConnectionInfo *ci; + unsigned int http_status = 0; + + ci = MHD_get_connection_info (connection, + MHD_CONNECTION_INFO_HTTP_STATUS); + if (NULL != ci) + http_status = ci->http_status; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Request for `%s' completed with HTTP status %u (%d)\n", + hc->url, + http_status, + toe); +#else + (void) connection; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Request for `%s' completed (%d)\n", + hc->url, + toe); +#endif + } + if (NULL != hc->cc) + hc->cc (hc); + GNUNET_free (hc); + *con_cls = NULL; +} + + +/** + * Function that queries MHD's select sets and + * starts the task waiting for them. + * + * @return task handle for the daemon + */ +static struct GNUNET_SCHEDULER_Task * +prepare_daemon (void) +{ + struct GNUNET_SCHEDULER_Task *ret; + fd_set rs; + fd_set ws; + fd_set es; + struct GNUNET_NETWORK_FDSet *wrs; + struct GNUNET_NETWORK_FDSet *wws; + int max; + MHD_UNSIGNED_LONG_LONG timeout; + int haveto; + struct GNUNET_TIME_Relative tv; + + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + wrs = GNUNET_NETWORK_fdset_create (); + wws = GNUNET_NETWORK_fdset_create (); + max = -1; + GNUNET_assert (MHD_YES == + MHD_get_fdset (mhd, + &rs, + &ws, + &es, + &max)); + haveto = MHD_get_timeout (mhd, &timeout); + if (haveto == MHD_YES) + tv = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + timeout); + else + tv = GNUNET_TIME_UNIT_FOREVER_REL; + GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); + GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding run_daemon select task\n"); + ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, + tv, + wrs, + wws, + &run_daemon, + NULL); + GNUNET_NETWORK_fdset_destroy (wrs); + GNUNET_NETWORK_fdset_destroy (wws); + return ret; +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be + * NULL!) + * @param config configuration + */ +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *config) +{ + int fh; + uint16_t port; + enum TALER_MHD_GlobalOptions go; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Starting frosix-httpd\n"); + go = TALER_MHD_GO_NONE; + if (FH_connection_close) + go |= TALER_MHD_GO_FORCE_CONNECTION_CLOSE; + FH_load_terms (config); + TALER_MHD_setup (go); + FH_cfg = config; + global_result = GNUNET_SYSERR; + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, + NULL); + if (GNUNET_OK != + TALER_config_get_amount (config, + "frosix", + "INSURANCE", + &FH_insurance)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "frosix", + "INSURANCE"); + GNUNET_SCHEDULER_shutdown (); + return; + } + if (GNUNET_OK != + TALER_config_get_amount (config, + "authorization-question", + "COST", + &FH_question_cost)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "authorization-question", + "COST"); + GNUNET_SCHEDULER_shutdown (); + return; + } + if (GNUNET_OK != + TALER_config_get_amount (config, + "frosix", + "ANNUAL_FEE", + &FH_annual_fee)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "frosix", + "ANNUAL_FEE"); + GNUNET_SCHEDULER_shutdown (); + return; + } + if (GNUNET_OK != + TALER_config_get_amount (config, + "frosix", + "SIGNATURE_CREATION_FEE", + &FH_signature_creation_fee)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "frosix", + "SIGNATURE_CREATION_FEE"); + GNUNET_SCHEDULER_shutdown (); + return; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (config, + "frosix-merchant-backend", + "PAYMENT_BACKEND_URL", + &FH_backend_url)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "frosix-merchant-backend", + "PAYMENT_BACKEND_URL"); + GNUNET_SCHEDULER_shutdown (); + return; + } + if ( (0 != strncasecmp ("https://", + FH_backend_url, + strlen ("https://"))) && + (0 != strncasecmp ("http://", + FH_backend_url, + strlen ("http://"))) ) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "frosix-merchant-backend", + "PAYMENT_BACKEND_URL", + "Must be HTTP(S) URL"); + GNUNET_SCHEDULER_shutdown (); + return; + } + + if ( (0 == strcasecmp ("https://", + FH_backend_url)) || + (0 == strcasecmp ("http://", + FH_backend_url)) ) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "frosix-merchant-backend", + "PAYMENT_BACKEND_URL", + "Must have domain name"); + GNUNET_SCHEDULER_shutdown (); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (config, + "frosix", + "FULFILLMENT_URL", + &FH_fulfillment_url)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "frosix", + "FULFILLMENT_URL"); + GNUNET_SCHEDULER_shutdown (); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (config, + "frosix", + "BUSINESS_NAME", + &FH_business_name)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "frosix", + "BUSINESS_NAME"); + GNUNET_SCHEDULER_shutdown (); + return; + } + + { + char *provider_salt; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (config, + "frosix", + "PROVIDER_SALT", + &provider_salt)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "frosix", + "PROVIDER_SALT"); + GNUNET_SCHEDULER_shutdown (); + return; + } + GNUNET_assert (GNUNET_YES == + GNUNET_CRYPTO_kdf (&FH_provider_salt, + sizeof (FH_provider_salt), + "frosix-provider-salt", + strlen ("frosix-provider-salt"), + provider_salt, + strlen (provider_salt), + NULL, + 0)); + GNUNET_free (provider_salt); + } + + { + char *secret_provider_salt; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (config, + "frosix", + "SECRET_PROVIDER_SALT", + &secret_provider_salt)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "frosix", + "SECRET_PROVIDER_SALT"); + GNUNET_SCHEDULER_shutdown (); + return; + } + GNUNET_assert (GNUNET_YES == + GNUNET_CRYPTO_kdf (&FH_secret_provider_salt, + sizeof (FH_secret_provider_salt), + "secret-frosix-provider-salt", + strlen ("secret-frosix-provider-salt"), + secret_provider_salt, + strlen (secret_provider_salt), + NULL, + 0)); + GNUNET_free (secret_provider_salt); + } + + { + char *private_signature_key; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (config, + "frosix", + "PRIVATE_SIG_KEY", + &private_signature_key)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "frosix", + "PRIVATE_SIG_KEY"); + GNUNET_SCHEDULER_shutdown (); + return; + } + + GNUNET_assert (GNUNET_YES == + GNUNET_STRINGS_string_to_data (private_signature_key, + strlen ( + private_signature_key), + &FH_priv_sig_key, + sizeof (FH_priv_sig_key))); + + GNUNET_CRYPTO_eddsa_key_get_public (&FH_priv_sig_key, + &FH_pub_sig_key); + + GNUNET_free (private_signature_key); + } + + /* setup HTTP client event loop */ + FH_ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, + &rc); + rc = GNUNET_CURL_gnunet_rc_create (FH_ctx); + if (NULL != userpass) + GNUNET_CURL_set_userpass (FH_ctx, + userpass); + if (NULL != keyfile) + GNUNET_CURL_set_tlscert (FH_ctx, + certtype, + certfile, + keyfile, + keypass); + if (NULL == apikey) + { + (void) GNUNET_CONFIGURATION_get_value_string (config, + "frosix-merchant-backend", + "API_KEY", + &apikey); + } + if (NULL != apikey) + { + char *auth_header; + + GNUNET_asprintf (&auth_header, + "%s: %s", + MHD_HTTP_HEADER_AUTHORIZATION, + apikey); + if (GNUNET_OK != + GNUNET_CURL_append_header (FH_ctx, + auth_header)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed so set %s header, trying without\n", + MHD_HTTP_HEADER_AUTHORIZATION); + } + GNUNET_free (auth_header); + } + + if (NULL == + (db = FROSIX_DB_plugin_load (config))) + { + GNUNET_SCHEDULER_shutdown (); + return; + } + + if (GNUNET_OK != + db->connect (db->cls)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Database not setup. Did you run anastasis-dbinit?\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + + fh = TALER_MHD_bind (config, + "frosix", + &port); + if ( (0 == port) && + (-1 == fh) ) + { + GNUNET_SCHEDULER_shutdown (); + return; + } + mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME | MHD_USE_DUAL_STACK, + port, + NULL, NULL, + &url_handler, NULL, + MHD_OPTION_LISTEN_SOCKET, fh, + MHD_OPTION_NOTIFY_COMPLETED, + &handle_mhd_completion_callback, NULL, + MHD_OPTION_CONNECTION_TIMEOUT, (unsigned + int) 10 /* 10s */, + MHD_OPTION_END); + if (NULL == mhd) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to launch HTTP service (port %u in use?), exiting.\n", + port); + GNUNET_SCHEDULER_shutdown (); + return; + } + global_result = GNUNET_OK; + mhd_task = prepare_daemon (); +} + + +/** + * The main function of the serve tool + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, + char *const *argv) +{ + enum GNUNET_GenericReturnValue res; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_option_string ('A', + "auth", + "USERNAME:PASSWORD", + "use the given USERNAME and PASSWORD for client authentication", + &userpass), + GNUNET_GETOPT_option_flag ('C', + "connection-close", + "force HTTP connections to be closed after each request", + &FH_connection_close), + GNUNET_GETOPT_option_string ('k', + "key", + "KEYFILE", + "file with the private TLS key for TLS client authentication", + &keyfile), + GNUNET_GETOPT_option_string ('p', + "pass", + "KEYFILEPASSPHRASE", + "passphrase needed to decrypt the TLS client private key file", + &keypass), + GNUNET_GETOPT_option_string ('K', + "apikey", + "APIKEY", + "API key to use in the HTTP request to the merchant backend", + &apikey), + GNUNET_GETOPT_option_string ('t', + "type", + "CERTTYPE", + "type of the TLS client certificate, defaults to PEM if not specified", + &certtype), + GNUNET_GETOPT_OPTION_END + }; + + /* FIRST get the libtalerutil initialization out + of the way. Then throw that one away, and force + the FROSIX defaults to be used! */ + (void) TALER_project_data_default (); + GNUNET_OS_init (FROSIX_project_data_default ()); + res = GNUNET_PROGRAM_run (argc, argv, + "frosix-httpd", + "Frosix HTTP interface", + options, &run, NULL); + if (GNUNET_SYSERR == res) + return 3; + if (GNUNET_NO == res) + return 0; + return (GNUNET_OK == global_result) ? 0 : 1; +} diff --git a/src/backend/frosix-httpd.h b/src/backend/frosix-httpd.h @@ -0,0 +1,231 @@ +/* + This file is part of Frosix + Copyright (C) 2019 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd.h + * @brief HTTP serving layer + * @author Christian Grothoff + */ +#ifndef FROSIX_HTTPD_H +#define FROSIX_HTTPD_H + +#include "platform.h" +#include "frost_high.h" +#include "frosix_backend.h" +#include <microhttpd.h> +#include <taler/taler_mhd_lib.h> +#include <gnunet/gnunet_mhd_compat.h> +#include <gnunet/gnunet_util_lib.h> + +/** + * For how many years do we allow users to store truth at most? Also + * how long we store things if the cost is zero. + */ +#define FROSIX_MAX_YEARS_STORAGE 5 + +/** + * @brief Struct describing an URL and the handler for it. + */ +struct FH_RequestHandler +{ + + /** + * URL the handler is for. + */ + const char *url; + + /** + * Method the handler is for, NULL for "all". + */ + const char *method; + + /** + * Mime type to use in reply (hint, can be NULL). + */ + const char *mime_type; + + /** + * Raw data for the @e handler + */ + const void *data; + + /** + * Number of bytes in @e data, 0 for 0-terminated. + */ + size_t data_size; + + + /** + * Function to call to handle the request. + * + * @param rh this struct + * @param connection the MHD connection to handle + * @return MHD result code + */ + MHD_RESULT (*handler)(struct FH_RequestHandler *rh, + struct MHD_Connection *connection); + + /** + * Default response code. + */ + unsigned int response_code; +}; + + +/** + * Each MHD response handler that sets the "connection_cls" to a + * non-NULL value must use a struct that has this struct as its first + * member. This struct contains a single callback, which will be + * invoked to clean up the memory when the contection is completed. + */ +struct TM_HandlerContext; + +/** + * Signature of a function used to clean up the context + * we keep in the "connection_cls" of MHD when handling + * a request. + * + * @param hc header of the context to clean up. + */ +typedef void +(*TM_ContextCleanup)(struct TM_HandlerContext *hc); + + +/** + * Each MHD response handler that sets the "connection_cls" to a + * non-NULL value must use a struct that has this struct as its first + * member. This struct contains a single callback, which will be + * invoked to clean up the memory when the connection is completed. + */ +struct TM_HandlerContext +{ + + /** + * Function to execute the handler-specific cleanup of the + * (typically larger) context. + */ + TM_ContextCleanup cc; + + /** + * Handler-specific context. + */ + void *ctx; + + /** + * Which request handler is handling this request? + */ + const struct FH_RequestHandler *rh; + + /** + * URL requested by the client, for logging. + */ + const char *url; + + /** + * Asynchronous request context id. + */ + struct GNUNET_AsyncScopeId async_scope_id; +}; + +/** + * Handle to the database backend. + */ +extern struct FROSIX_DatabasePlugin *db; + + +/** + * Annual fee for the backup account. + */ +extern struct TALER_Amount FH_annual_fee; + +/** + * Fee for a truth upload. + */ +extern struct TALER_Amount FH_signature_creation_fee; + +/** + * Amount of insurance. + */ +extern struct TALER_Amount FH_insurance; + +/** + * Cost for secure question truth download. + */ +extern struct TALER_Amount FH_question_cost; + +/** + * Our Taler backend to process payments. + */ +extern char *FH_backend_url; + +/** + * Heap for processing timeouts of requests. + */ +extern struct GNUNET_CONTAINER_Heap *FH_to_heap; + +/** + * Our configuration. + */ +extern const struct GNUNET_CONFIGURATION_Handle *FH_cfg; + +/** + * Number of policy uploads permitted per annual fee payment. + */ +extern unsigned long long FH_post_counter; + +/** + * Our fulfillment URL + */ +extern char *FH_fulfillment_url; + +/** + * Our business name. + */ +extern char *FH_business_name; + +/** + * Our provider salt. + */ +extern struct FROSIX_ProviderSaltP FH_provider_salt; + +/** + * Our public key +*/ +extern struct GNUNET_CRYPTO_EddsaPublicKey FH_pub_sig_key; + +/** + * Our context for making HTTP requests. + */ +extern struct GNUNET_CURL_Context *FH_ctx; + + +/** + * Kick MHD to run now, to be called after MHD_resume_connection(). + * Basically, we need to explicitly resume MHD's event loop whenever + * we made progress serving a request. This function re-schedules + * the task processing MHD's activities to run immediately. + * + * @param cls NULL + */ +void +FH_trigger_daemon (void *cls); + +/** + * Kick GNUnet Curl scheduler to begin curl interactions. + */ +void +FH_trigger_curl (void); + +#endif +\ No newline at end of file diff --git a/src/backend/frosix-httpd_auth-challenge.c b/src/backend/frosix-httpd_auth-challenge.c @@ -0,0 +1,448 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_commitment.c + * @brief functions to handle incoming requests on /auth-challenge + * @author Joel Urech + */ +#include "frosix-httpd_auth.h" +#include "frosix-httpd.h" +#include "frost_high.h" +#include "frost_low.h" +#include <taler/taler_util.h> +#include <gnunet/gnunet_util_lib.h> +#include "frosix_database_plugin.h" +#include "frosix_util_lib.h" +#include "frosix_authorization_lib.h" + +#define HASHCONTEXT "FROSIX-DKG" + +/** + * Context for an dkg commitment operation +*/ +struct ChallengeContext +{ + /** + * + */ + struct FROSIX_EncryptionKey encryption_key; + + /** + * + */ + struct FROST_MessageHash message_hash; + + /** + * + */ + struct GNUNET_HashCode challenge_salt; + + /** + * + */ + const char *challenge_method; + + /** + * + */ + const char *challenge_data; + + /** + * Id of the request, hash of all submitted values. + */ + struct FROSIX_ChallengeRequestIdP request_id; + + /** + * Our handler context + */ + struct TM_HandlerContext *hc; + + /** + * Uploaded JSON data, NULL if upload is not yet complete. + */ + json_t *json; + + /** + * Post parser context. + */ + void *post_ctx; + + /** + * Connection handle for closing or resuming + */ + struct MHD_Connection *connection; + + /** + * Reference to the authorization plugin which was loaded + */ + struct FROSIX_AuthorizationPlugin *authorization; + + /** + * Status of the authorization + */ + struct FROSIX_AUTHORIZATION_State *as; + + /** + * Random authorization code we are using. + */ + uint64_t code; + + /** + * FIXME + */ + struct FROSIX_ChallengeIdP challenge_id; +}; + + +/** + * Generate a response telling the client that answering this + * challenge failed because the rate limit has been exceeded. + * + * @param gc request to answer for + * @return MHD status code + */ +static MHD_RESULT +reply_rate_limited (const struct ChallengeContext *cc) +{ + return TALER_MHD_REPLY_JSON_PACK ( + cc->connection, + MHD_HTTP_TOO_MANY_REQUESTS, + TALER_MHD_PACK_EC (TALER_EC_GENERIC_TIMEOUT), + GNUNET_JSON_pack_uint64 ("request_limit", + cc->authorization->retry_counter), + GNUNET_JSON_pack_time_rel ("request_frequency", + cc->authorization->code_rotation_period)); +} + + +/** + * Run the authorization method-specific 'process' function and continue + * based on its result with generating an HTTP response. + * + * @param connection the connection we are handling + * @param gc our overall handler context + */ +static MHD_RESULT +run_authorization_process (struct MHD_Connection *connection, + struct ChallengeContext *gc) +{ + enum FROSIX_AUTHORIZATION_ChallengeResult ret; + enum GNUNET_DB_QueryStatus qs; + + if (NULL == gc->authorization->challenge) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (gc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_METHOD_INVALID, + "challenge method not implemented for authorization method"); + } + ret = gc->authorization->challenge (gc->as, + connection); + switch (ret) + { + case FROSIX_AUTHORIZATION_CRES_SUCCESS: + /* Challenge sent successfully */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Authorization request %llu for %s sent successfully\n", + (unsigned long long) gc->code, + TALER_B2S (&gc->challenge_id)); + qs = db->mark_challenge_sent (db->cls, + &gc->challenge_id, + gc->code); + GNUNET_break (0 < qs); + gc->authorization->cleanup (gc->as); + gc->as = NULL; + return MHD_YES; + case FROSIX_AUTHORIZATION_CRES_FAILED: + gc->authorization->cleanup (gc->as); + gc->as = NULL; + return MHD_YES; + case FROSIX_AUTHORIZATION_CRES_SUSPENDED: + /* connection was suspended */ + // gc_suspended (gc); + return MHD_YES; + case FROSIX_AUTHORIZATION_CRES_SUCCESS_REPLY_FAILED: + /* Challenge sent successfully */ + qs = db->mark_challenge_sent (db->cls, + &gc->challenge_id, + gc->code); + GNUNET_break (0 < qs); + gc->authorization->cleanup (gc->as); + gc->as = NULL; + return MHD_NO; + case FROSIX_AUTHORIZATION_CRES_FAILED_REPLY_FAILED: + gc->authorization->cleanup (gc->as); + gc->as = NULL; + return MHD_NO; + } + GNUNET_break (0); + return MHD_NO; +} + + +MHD_RESULT +FH_handler_auth_challenge_post ( + struct MHD_Connection *connection, + struct TM_HandlerContext *hc, + const struct FROSIX_ChallengeRequestIdP *id, + const char *auth_challenge_data, + size_t *auth_challenge_data_size) +{ + enum GNUNET_GenericReturnValue res; + struct ChallengeContext *cc = hc->ctx; + + if (NULL == cc) + { + cc = GNUNET_new (struct ChallengeContext); + cc->connection = connection; + hc->ctx = cc; + } + + /* parse request body */ + if (NULL == cc->json) + { + res = TALER_MHD_parse_post_json (connection, + &cc->post_ctx, + auth_challenge_data, + auth_challenge_data_size, + &cc->json); + if (GNUNET_SYSERR == res) + { + GNUNET_break (0); + return MHD_NO; + } + if ((GNUNET_NO == res || + (NULL == cc->json))) + { + return MHD_YES; + } + } + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("encryption_key", + &cc->encryption_key), + GNUNET_JSON_spec_string ("auth_method", + &cc->challenge_method), + GNUNET_JSON_spec_string ("auth_data", + &cc->challenge_data), + GNUNET_JSON_spec_fixed_auto ("auth_nonce", + &cc->challenge_salt), + GNUNET_JSON_spec_fixed_auto ("message_hash", + &cc->message_hash), + GNUNET_JSON_spec_end () + }; + + res = TALER_MHD_parse_json_data (connection, + cc->json, + spec); + if (GNUNET_SYSERR == res) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "Unable to parse request body"); + } + if (GNUNET_NO == res) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to parse request body"); + } + + /* validate request id */ + { + struct FROSIX_ChallengeRequestIdP req_id; + FROSIX_compute_challenge_request_id (&req_id, + &cc->encryption_key, + &cc->message_hash); + + if (GNUNET_OK != FROST_hash_cmp (&req_id.id, + &id->id)) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "ID in URL not matching data in body"); + } + } + + { + /* hash encryption_key to get id from entry in db */ + struct FROST_HashCode enc_key_hash; + FROSIX_hash_encryption_key (&enc_key_hash, + &cc->encryption_key); + + struct FROSIX_ChallengeHashP auth_hash_db; + enum GNUNET_DB_QueryStatus qs; + qs = db->get_auth_hash (db->cls, + &enc_key_hash, + &auth_hash_db); + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "auth_data_select"); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + + /* hash received auth data */ + struct FROSIX_ChallengeHashP auth_hash_req; + FROSIX_compute_auth_hash (&auth_hash_req, + cc->challenge_data, + &cc->challenge_salt); + + /* compare auth hash from db with hash of received data*/ + if (GNUNET_OK != FROSIX_gnunet_hash_cmp (&auth_hash_req.hash, + &auth_hash_db.hash)) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Got invalid data from DB"); + } + + /* compute challenge id */ + FROSIX_compute_challenge_id (&cc->challenge_id, + &enc_key_hash, + &cc->message_hash); + } + + /* try to load authorization plugin */ + cc->authorization + = FROSIX_authorization_plugin_load (cc->challenge_method, + db, + FH_cfg); + + if (NULL == cc->authorization) + { + MHD_RESULT ret; + + ret = TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_METHOD_INVALID, + cc->challenge_method); + return ret; + } + + /* use plugin to check if challenge data is valid! */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "No challenge provided, creating fresh challenge\n"); + { + enum GNUNET_GenericReturnValue ret; + + ret = cc->authorization->validate (cc->authorization->cls, + connection, + cc->challenge_method, + cc->challenge_data, + strlen (cc->challenge_data)); + switch (ret) + { + case GNUNET_OK: + /* data valid, continued below */ + break; + case GNUNET_NO: + /* data invalid, reply was queued */ + return MHD_YES; + case GNUNET_SYSERR: + /* data invalid, reply was NOT queued */ + return MHD_NO; + } + } + + /* Setup challenge and begin authorization process */ + { + struct GNUNET_TIME_Timestamp transmission_date; + enum GNUNET_DB_QueryStatus qs; + + qs = db->create_challenge_code (db->cls, + &cc->challenge_id, + cc->authorization->code_rotation_period, + cc->authorization->code_validity_period, + cc->authorization->retry_counter, + &transmission_date, + &cc->code); + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return TALER_MHD_reply_with_error (cc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "create_challenge_code"); + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + /* 0 == retry_counter of existing challenge => rate limit exceeded */ + return reply_rate_limited (cc); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + /* challenge code was stored successfully*/ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Created fresh challenge\n"); + break; + } + + if (GNUNET_TIME_relative_cmp ( + GNUNET_TIME_absolute_get_duration ( + transmission_date.abs_time), + <, + cc->authorization->code_retransmission_frequency) ) + { + /* Too early for a retransmission! */ + return TALER_MHD_REPLY_JSON_PACK ( + cc->connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_string ("challenge_type", + "TAN_ALREADY_SENT")); + } + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Beginning authorization process\n"); + cc->as = cc->authorization->start (cc->authorization->cls, + &FH_trigger_daemon, + NULL, + &cc->challenge_id, + cc->code, + cc->challenge_data, + strlen (cc->challenge_data)); + + if (NULL == cc->as) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (cc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_UNEXPECTED_REQUEST_ERROR, + NULL); + } + + return run_authorization_process (connection, + cc); +} +\ No newline at end of file diff --git a/src/backend/frosix-httpd_auth.h b/src/backend/frosix-httpd_auth.h @@ -0,0 +1,37 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_auth.h + * @brief functions to handle incoming requests on /auth-challenge + * @author Joel Urech + */ +#ifndef FROSIX_HTTPD_AUTH_H +#define FROSIX_HTTPD_AUTH_H +#include "frosix-httpd.h" +#include "frosix_crypto.h" +#include "frosix_util_lib.h" +#include <microhttpd.h> +#include <taler/taler_mhd_lib.h> + +MHD_RESULT +FH_handler_auth_challenge_post ( + struct MHD_Connection *connection, + struct TM_HandlerContext *hc, + const struct FROSIX_ChallengeRequestIdP *id, + const char *dkg_commitment_data, + size_t *dkg_commitment_data_size); + +#endif +\ No newline at end of file diff --git a/src/backend/frosix-httpd_common.c b/src/backend/frosix-httpd_common.c @@ -0,0 +1,224 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_dkg-commitment_common.c + * @brief functions to handle incoming requests on /seed + * @author Joel Urech + */ +#include "frosix-httpd_dkg.h" +#include "frosix_service.h" +#include "keygen.h" +#include "frost_low.h" +#include <taler/taler_util.h> +#include <gnunet/gnunet_util_lib.h> + + +static enum GNUNET_GenericReturnValue +generate_commitment_and_shares ( + struct FROST_DkgCommitment *dkg_comm, + struct FROST_DkgShare dkg_shares[], + const struct FROST_DkgContextString *context_string, + const struct FROST_HashCode *additional_data, + uint8_t identifier, + uint8_t threshold, + uint8_t num_of_participants) +{ + if (GNUNET_OK != FROST_initialize_dkg_commitment (dkg_comm, + identifier, + threshold)) + return GNUNET_NO; + + return FROST_keygen_begin (dkg_comm, + dkg_shares, + context_string, + additional_data, + identifier, + num_of_participants, + threshold); +} + +enum GNUNET_GenericReturnValue +FROSIX_dkg_commitment_generate_ ( + struct FROST_DkgCommitment *dkg_comm, + const struct FROST_DkgContextString *context_string, + const struct FROST_HashCode *additional_data, + uint8_t identifier, + uint8_t threshold, + uint8_t num_of_participants) +{ + struct FROST_DkgShare dkg_shares[num_of_participants]; + + enum GNUNET_GenericReturnValue ret = generate_commitment_and_shares (dkg_comm, + dkg_shares, + context_string, + additional_data, + identifier, + threshold, + num_of_participants); + + return ret; +} + +enum GNUNET_GenericReturnValue +FROSIX_dkg_shares_generate_ ( + struct FROST_DkgShare dkg_shares[], + const struct FROST_DkgContextString *context_string, + const struct FROST_HashCode *additional_data, + uint8_t identifier, + uint8_t threshold, + uint8_t num_of_participants) +{ + struct FROST_DkgCommitment dkg_comm; + + enum GNUNET_GenericReturnValue ret = + generate_commitment_and_shares (&dkg_comm, + dkg_shares, + context_string, + additional_data, + identifier, + threshold, + num_of_participants); + + FROST_free_dkg_commitment (&dkg_comm, + 1); + + return ret; +} + +enum GNUNET_GenericReturnValue +FROSIX_dkg_derive_context_string_ ( + struct FROST_DkgContextString *resulting_context_string, + uint8_t provider_index, + uint8_t threshold, + const struct FROSIX_DkgContextStringP *input_context_string, + const struct FROSIX_ChallengeHashP *challenge_hash, + const struct GNUNET_CRYPTO_EddsaPublicKey provider_public_keys[], + size_t length, + const struct FROSIX_SecretProviderSaltP *secret_provider_salt) +{ + /* get hash of all public keys, concatenated with provider index and threshold + */ + struct GNUNET_HashContext *hash_context = GNUNET_CRYPTO_hash_context_start (); + + for (unsigned int i = 0; i < length; i++) + { + GNUNET_CRYPTO_hash_context_read (hash_context, + &provider_public_keys[i], + sizeof (*provider_public_keys)); + } + GNUNET_CRYPTO_hash_context_read (hash_context, + &provider_index, + sizeof (provider_index)); + GNUNET_CRYPTO_hash_context_read (hash_context, + &threshold, + sizeof (threshold)); + + struct GNUNET_HashCode pk_hash; + GNUNET_CRYPTO_hash_context_finish (hash_context, + &pk_hash); + + /* derive entropy for our key generation */ + return GNUNET_CRYPTO_kdf (resulting_context_string, + sizeof (*resulting_context_string), + secret_provider_salt, + sizeof (*secret_provider_salt), + input_context_string, + sizeof (*input_context_string), + challenge_hash, + sizeof (*challenge_hash), + &pk_hash, + sizeof (pk_hash), + NULL); +} + +enum GNUNET_GenericReturnValue +FROSIX_dkg_validate_request_id_ ( + const struct FROSIX_DkgRequestIdP *request_id, + const struct FROSIX_DkgContextStringP *context_string, + const struct FROSIX_ChallengeHashP *challenge_hash, + const struct FROSIX_ProviderSaltP *provider_salt, + uint8_t identifier, + uint8_t num_of_participants, + uint8_t threshold) +{ + /* is request_id == H(context_string || + auth_data_hash_salted || + identifier || + num_of_participants || + threshold || + public_server_salt || + "FROSIX-DKG" )*/ + struct FROST_HashState check_id_state; + struct FROST_HashCode check_id; + + FROST_hash_init (&check_id_state); + FROST_hash_hash_update (&check_id_state, + &context_string->hash); + FROST_hash_fixed_update (&check_id_state, + &challenge_hash->hash, + sizeof (*challenge_hash)); + FROST_hash_uint8_update (&check_id_state, + identifier); + FROST_hash_uint8_update (&check_id_state, + num_of_participants); + FROST_hash_uint8_update (&check_id_state, + threshold); + FROST_hash_fixed_update (&check_id_state, + provider_salt, + sizeof (*provider_salt)); + FROST_hash_fixed_update (&check_id_state, + "FROSIX-DKG-ID", + strlen ("FROSIX-DKG-ID")); + FROST_hash_final (&check_id_state, + &check_id); + + return FROST_hash_cmp (&request_id->id, + &check_id); +} + +void +FROSIX_raw_key_to_struct (struct FROST_KeyPair *key_pair, + const struct FROSIX_KeyDataRaw *decrypted) +{ + memcpy (&key_pair->my_sk, + &decrypted->bytes[0], + sizeof (key_pair->my_sk)); + memcpy (&key_pair->group_pk, + &decrypted->bytes[sizeof (key_pair->my_sk)], + sizeof (key_pair->my_pk)); + FROST_base_mul_scalar (&key_pair->my_pk, + &key_pair->my_sk); +} + + +void +FROSIX_compute_db_commitment_id (struct GNUNET_HashCode *db_id, + const struct FROST_HashCode *enc_key_hash, + const struct FROST_Commitment *commitment) +{ + struct GNUNET_HashContext *hc = GNUNET_CRYPTO_hash_context_start (); + GNUNET_CRYPTO_hash_context_read (hc, + enc_key_hash, + sizeof (*enc_key_hash)); + GNUNET_CRYPTO_hash_context_read (hc, + &commitment->hiding_commitment, + sizeof (commitment->hiding_commitment)); + GNUNET_CRYPTO_hash_context_read (hc, + &commitment->binding_commitment, + sizeof (commitment->binding_commitment)); + GNUNET_CRYPTO_hash_context_finish (hc, + db_id); +} +\ No newline at end of file diff --git a/src/backend/frosix-httpd_config.c b/src/backend/frosix-httpd_config.c @@ -0,0 +1,125 @@ +/* + This file is part of Frosix + Copyright (C) 2020, 2021 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_config.c + * @brief headers for /terms handler + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + */ +#include "platform.h" +#include <jansson.h> +#include "frosix-httpd_config.h" +#include "frosix-httpd.h" +#include "frosix_authorization_plugin.h" +#include "frosix_authorization_lib.h" +#include <taler/taler_json_lib.h> + + +/** + * Add enabled methods and their fees to the ``/config`` response. + * + * @param[in,out] cls a `json_t` array to build + * @param section configuration section to inspect + */ +static void +add_methods (void *cls, + const char *section) +{ + json_t *method_arr = cls; + struct FROSIX_AuthorizationPlugin *p; + json_t *method; + + if (0 != strncasecmp (section, + "authorization-", + strlen ("authorization-"))) + return; + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_yesno (FH_cfg, + section, + "ENABLED")) + return; + section += strlen ("authorization-"); + p = FROSIX_authorization_plugin_load (section, + db, + FH_cfg); + if (NULL == p) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to load authorization plugin `%s'\n", + section); + return; + } + method = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + section), + TALER_JSON_pack_amount ("cost", + &p->cost)); + GNUNET_assert ( + 0 == + json_array_append_new (method_arr, + method)); +} + + +MHD_RESULT +FH_handler_config (struct FH_RequestHandler *rh, + struct MHD_Connection *connection) +{ + json_t *method_arr = json_array (); + + GNUNET_assert (NULL != method_arr); + { + json_t *method; + + method = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "question"), + TALER_JSON_pack_amount ("cost", + &FH_question_cost)); + GNUNET_assert ( + 0 == + json_array_append_new (method_arr, + method)); + } + GNUNET_CONFIGURATION_iterate_sections (FH_cfg, + &add_methods, + method_arr); + return TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_string ("name", + "frosix"), + GNUNET_JSON_pack_string ("version", + "0:0:0"), + GNUNET_JSON_pack_string ("business_name", + FH_business_name), + GNUNET_JSON_pack_array_steal ("methods", + method_arr), + TALER_JSON_pack_amount ("annual_fee", + &FH_annual_fee), + TALER_JSON_pack_amount ("signature_creation_fee", + &FH_signature_creation_fee), + TALER_JSON_pack_amount ("liability_limit", + &FH_insurance), + GNUNET_JSON_pack_data_auto ("provider_salt", + &FH_provider_salt), + GNUNET_JSON_pack_data_auto ("public_key", + &FH_pub_sig_key)); +} + + +/* end of frosix-httpd_config.c */ diff --git a/src/backend/frosix-httpd_config.h b/src/backend/frosix-httpd_config.h @@ -0,0 +1,41 @@ +/* + This file is part of Frosix + Copyright (C) 2020 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_config.h + * @brief headers for /terms handler + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + */ +#ifndef FROSIX_HTTPD_CONFIG_H +#define FROSIX_HTTPD_CONFIG_H +#include <microhttpd.h> +#include "frosix-httpd.h" + +/** + * Manages a /config call. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @return MHD result code + */ +MHD_RESULT +FH_handler_config (struct FH_RequestHandler *rh, + struct MHD_Connection *connection); + +#endif + +/* end of frosix-httpd_config.h */ diff --git a/src/backend/frosix-httpd_dkg-commitment.c b/src/backend/frosix-httpd_dkg-commitment.c @@ -0,0 +1,379 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_commitment.c + * @brief functions to handle incoming requests on /dkg-commitment + * @author Joel Urech + */ +#include "frosix-httpd_dkg.h" +#include "frosix-httpd.h" +#include "frosix_service.h" +#include "keygen.h" +#include <taler/taler_util.h> +#include <gnunet/gnunet_util_lib.h> + +#define HASHCONTEXT "FROSIX-DKG" + +/** + * Context for an dkg commitment operation +*/ +struct DkgCommitmentContext +{ + /** + * Our unique identifier value in the dkg process. + */ + uint8_t provider_index; + + /** + * Number of providers which has to collaborate in order to generate a valid signature. + */ + uint8_t threshold; + + /** + * Total number of providers participating in the distributed key generation process. + */ + uint8_t num_of_participants; + + /** + * High entropy string, which should be only used for one distributed key generation process. + * The resulting commitment will be deterministically derived from this context string. + */ + struct FROSIX_DkgContextStringP context_string; + + /** + * Salted hash of the chosen challenge method. + */ + struct FROSIX_ChallengeHashP auth_hash; + + /** + * Id of the request, hash of all submitted values. + */ + struct FROSIX_DkgRequestIdP request_id; + + /** + * + */ + struct FROSIX_ProviderSaltP provider_salt; + + /** + * + */ + struct FROSIX_SecretProviderSaltP secret_provider_salt; + + /** + * + */ + struct GNUNET_CRYPTO_EddsaPublicKey pub_sig_key; + + /** + * + */ + struct GNUNET_CRYPTO_EddsaPrivateKey priv_sig_key; + + /** + * Our handler context + */ + struct TM_HandlerContext *hc; + + /** + * Uploaded JSON data, NULL if upload is not yet complete. + */ + json_t *json; + + /** + * Post parser context. + */ + void *post_ctx; + + /** + * Connection handle for closing or resuming + */ + struct MHD_Connection *connection; + + /** + * When should this request time out? + */ + struct GNUNET_TIME_Absolute timeout; + +}; + + +/** + * Return the generated dkg_commitment + * + * @param connection + * @param dkg_comm + * @return +*/ +static MHD_RESULT +return_dkg_commitment ( + struct MHD_Connection *connection, + const struct GNUNET_CRYPTO_EddsaPublicKey *pub_sig_key, + const struct FROST_DkgCommitment *dkg_comm) +{ + // Prepare commit + json_t *commits; + commits = json_array (); + GNUNET_assert (NULL != commits); + + for (int i = 0; i < dkg_comm->shares_commitments_length; i++) + { + GNUNET_assert (0 == + json_array_append ( + commits, + GNUNET_JSON_from_data_auto (&dkg_comm->share_comm[i]))); + } + + // Return everything + return TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_CREATED, + GNUNET_JSON_pack_uint64 ("provider_index", + dkg_comm->identifier), + GNUNET_JSON_pack_array_steal ("dkg_commitment", + commits), + GNUNET_JSON_pack_data_auto ("zkp_r", + &dkg_comm->zkp.r), + GNUNET_JSON_pack_data_auto ("zkp_z", + &dkg_comm->zkp.z), + GNUNET_JSON_pack_data_auto ("public_key", + pub_sig_key)); +} + +MHD_RESULT +FH_handler_dkg_commitment_post ( + struct MHD_Connection *connection, + struct TM_HandlerContext *hc, + const struct FROSIX_DkgRequestIdP *dkg_id, + const struct FROSIX_ProviderSaltP *provider_salt, + const struct FROSIX_SecretProviderSaltP *secret_provider_salt, + const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_sig_key, + const struct GNUNET_CRYPTO_EddsaPublicKey *pub_sig_key, + const char *dkg_commitment_data, + size_t *dkg_commitment_data_size) +{ + enum GNUNET_GenericReturnValue res; + struct DkgCommitmentContext *dc = hc->ctx; + json_t *json_ppk = NULL; + + if (NULL == dc) + { + dc = GNUNET_new (struct DkgCommitmentContext); + dc->connection = connection; + dc->request_id = *dkg_id; + dc->provider_salt = *provider_salt; + dc->secret_provider_salt = *secret_provider_salt; + dc->priv_sig_key = *priv_sig_key; + dc->pub_sig_key = *pub_sig_key; + hc->ctx = dc; + } + + /* parse request body */ + if (NULL == dc->json) + { + res = TALER_MHD_parse_post_json (connection, + &dc->post_ctx, + dkg_commitment_data, + dkg_commitment_data_size, + &dc->json); + if (GNUNET_SYSERR == res) + { + GNUNET_break (0); + return MHD_NO; + } + if ((GNUNET_NO == res || + (NULL == dc->json))) + { + return MHD_YES; + } + } + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_uint8 ("provider_index", + &dc->provider_index), + GNUNET_JSON_spec_uint8 ("threshold", + &dc->threshold), + GNUNET_JSON_spec_fixed_auto ("context_string", + &dc->context_string), + GNUNET_JSON_spec_fixed_auto ("auth_hash", + &dc->auth_hash), + GNUNET_JSON_spec_json ("providers_public_keys", + &json_ppk), + GNUNET_JSON_spec_end () + }; + + res = TALER_MHD_parse_json_data (connection, + dc->json, + spec); + if (GNUNET_SYSERR == res) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "Unable to parse request body"); + } + if (GNUNET_NO == res) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to parse request body"); + } + + /* check number of submitted provider public keys*/ + if (254 < json_array_size (json_ppk)) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Too many provider public keys"); + } + + /* set number of participants */ + dc->num_of_participants = json_array_size (json_ppk); + + /* validate provider index, threshold and num_of_participants */ + if (GNUNET_OK != FROST_validate_dkg_params (dc->provider_index, + dc->threshold, + dc->num_of_participants)) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Parameters out ouf bound"); + } + + /* Check if called id is matching the send data */ + if (GNUNET_OK != FROSIX_dkg_validate_request_id_ ( + &dc->request_id, + &dc->context_string, + &dc->auth_hash, + &dc->provider_salt, + dc->provider_index, + dc->num_of_participants, + dc->threshold)) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "ID in URL not matching data in body"); + } + + /* parse providers public keys */ + struct GNUNET_CRYPTO_EddsaPublicKey + providers_public_keys[dc->num_of_participants]; + for (unsigned int i = 0; i < dc->num_of_participants; i++) + { + struct GNUNET_JSON_Specification ppk_spec[] = { + GNUNET_JSON_spec_fixed_auto (NULL, + &providers_public_keys[i]), + GNUNET_JSON_spec_end () + }; + + res = TALER_MHD_parse_json_array (connection, + json_ppk, + ppk_spec, + i, + -1); + + if (GNUNET_SYSERR == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (ppk_spec); + GNUNET_break (0); + return MHD_NO; + } + if (GNUNET_NO == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (ppk_spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to parse request body"); + } + + GNUNET_JSON_parse_free (ppk_spec); + } + + GNUNET_JSON_parse_free (spec); + + /* FIXME: check if any of the submitted public key is ours */ + + /* derive the final context string */ + struct FROST_DkgContextString cs_h; + if (GNUNET_YES != FROSIX_dkg_derive_context_string_ ( + &cs_h, + dc->provider_index, + dc->threshold, + &dc->context_string, + &dc->auth_hash, + providers_public_keys, + dc->num_of_participants, + &dc->secret_provider_salt)) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "Derive context string"); + } + + /* hash public key */ + struct FROST_HashState h_s; + struct FROST_HashCode pub_key_hash; + FROST_hash_init (&h_s); + FROST_hash_fixed_update (&h_s, + &dc->pub_sig_key, + sizeof (dc->pub_sig_key)); + FROST_hash_final (&h_s, + &pub_key_hash); + + /* create shares with zkp including hashed pk */ + struct FROST_DkgCommitment dkg_commitment; + + if (GNUNET_OK != FROSIX_dkg_commitment_generate_ (&dkg_commitment, + &cs_h, + &pub_key_hash, + dc->provider_index, + dc->threshold, + dc->num_of_participants)) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "Generate DKG commitment"); + } + + res = return_dkg_commitment (connection, + &dc->pub_sig_key, + &dkg_commitment); + + FROST_free_dkg_commitment (&dkg_commitment, + 1); + + return res; +} +\ No newline at end of file diff --git a/src/backend/frosix-httpd_dkg-key.c b/src/backend/frosix-httpd_dkg-key.c @@ -0,0 +1,738 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_dkg-key.c + * @brief functions to handle incoming requests on /dkg-key + * @author Joel Urech + */ +#include "frosix-httpd_dkg.h" +#include "frosix-httpd.h" +#include "frosix_database_plugin.h" +#include "frosix_service.h" +#include "keygen.h" +#include <taler/taler_util.h> +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_db_lib.h> + + +struct DkgKeyContext +{ + /** + * + */ + uint8_t provider_index; + + /** + * + */ + uint8_t threshold; + + /** + * + */ + uint8_t num_of_participants; + + /** + * + */ + struct FROSIX_DkgContextStringP context_string; + + /** + * + */ + struct FROSIX_ChallengeHashP auth_hash; + + /** + * + */ + struct FROSIX_EncryptionKey pre_enc_key; + + /** + * + */ + uint8_t expiration; + + + /** + * + */ + struct FROSIX_DkgRequestIdP request_id; + + /** + * + */ + struct FROSIX_ProviderSaltP provider_salt; + + /** + * + */ + struct FROSIX_SecretProviderSaltP secret_provider_salt; + + /** + * + */ + struct GNUNET_CRYPTO_EddsaPrivateKey priv_sig_key; + + /** + * + */ + struct FROST_DkgShare *dkg_shares; + + /** + * Our handler context + */ + struct TM_HandlerContext *hc; + + /** + * Uploaded JSON data, NULL if upload is not yet complete. + */ + json_t *json; + + /** + * Post parser context. + */ + void *post_ctx; + + /** + * Connection handle for closing or resuming + */ + struct MHD_Connection *connection; + + /** + * When should this request time out? + */ + struct GNUNET_TIME_Absolute timeout; +}; + + +static enum GNUNET_GenericReturnValue +derive_encryption_key ( + struct FROSIX_EncryptionKey *enc_key, + const struct FROSIX_EncryptionKey *pre_enc_key, + const struct FROST_PublicKey *pk, + const struct FROSIX_ProviderSaltP *provider_salt, + uint8_t provider_index) +{ + return GNUNET_CRYPTO_kdf (enc_key, + sizeof (*enc_key), + "FROSIX-KEY", + strlen ("FROSIX-KEY"), + pre_enc_key, + sizeof (*pre_enc_key), + pk, + sizeof (*pk), + provider_salt, + sizeof (*provider_salt), + &provider_index, + sizeof (provider_index), + NULL, + 0); +} + +static void +generate_key_pair (struct FROST_KeyPair *key_pair, + struct FROST_DkgShare other_shares[], + const struct FROST_DkgShare my_shares[], + const struct FROST_DkgCommitment dkg_commitments[], + uint8_t my_index, + uint8_t threshold, + uint8_t num_of_participants) +{ + memcpy (&other_shares[my_index - 1].share, + &my_shares[my_index - 1].share, + sizeof (my_shares[my_index - 1].share)); + + FROST_keygen_finalize (key_pair, + my_index, + other_shares, + dkg_commitments, + num_of_participants); +} + +static MHD_RESULT +store_key_data (struct DkgKeyContext *dc, + struct FROST_HashCode *enc_key_hash, + struct FROSIX_EncryptionKey *enc_key, + struct FROST_KeyPair *key_pair) +{ + /* Copy key data together */ + struct FROSIX_KeyDataRaw raw_data; + memcpy (&raw_data.bytes[0], + &key_pair->my_sk, + sizeof (key_pair->my_sk)); + + memcpy (&raw_data.bytes[sizeof key_pair->my_sk], + &key_pair->group_pk, + sizeof (key_pair->group_pk)); + + /* Generate nonce */ + struct FROSIX_EncryptionNonceP nonce; + FROSIX_secretbox_nonce_randombytes (&nonce); + + /* Encrypt key data */ + struct FROSIX_KeyDataEncrypted ciphertext; + FROSIX_secretbox_keydata (&ciphertext, + &raw_data, + &nonce, + enc_key); + + /* store key data */ + enum GNUNET_DB_QueryStatus qs; + qs = db->store_key (db->cls, + enc_key_hash, + &nonce, + &ciphertext, + &dc->auth_hash, + dc->expiration, + dc->provider_index); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_break (0); + return TALER_MHD_reply_with_error (dc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_INVARIANT_FAILURE, + "store key"); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + return MHD_HTTP_OK; +} + + +MHD_RESULT +FH_handler_dkg_key_post ( + struct MHD_Connection *connection, + struct TM_HandlerContext *hc, + const struct FROSIX_DkgRequestIdP *dkg_id, + const struct FROSIX_ProviderSaltP *provider_salt, + const struct FROSIX_SecretProviderSaltP *secret_provider_salt, + const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_sig_key, + const char *dkg_key_data, + size_t *dkg_key_data_size) +{ + enum GNUNET_GenericReturnValue res; + struct DkgKeyContext *dc = hc->ctx; + json_t *json_ppk = NULL; + json_t *shares = NULL; + size_t share_n_comm_length; + + if (NULL == dc) + { + dc = GNUNET_new (struct DkgKeyContext); + dc->connection = connection; + dc->request_id = *dkg_id; + dc->provider_salt = *provider_salt; + dc->secret_provider_salt = *secret_provider_salt; + dc->priv_sig_key = *priv_sig_key; + hc->ctx = dc; + } + + /* parse request body */ + if (NULL == dc->json) + { + res = TALER_MHD_parse_post_json (dc->connection, + &dc->post_ctx, + dkg_key_data, + dkg_key_data_size, + &dc->json); + if (GNUNET_SYSERR == res) + { + GNUNET_break (0); + return MHD_NO; + } + if ((GNUNET_NO == res || + (NULL == dc->json))) + { + return MHD_YES; + } + } + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_uint8 ("provider_index", + &dc->provider_index), + GNUNET_JSON_spec_uint8 ("threshold", + &dc->threshold), + GNUNET_JSON_spec_fixed_auto ("context_string", + &dc->context_string), + GNUNET_JSON_spec_fixed_auto ("auth_hash", + &dc->auth_hash), + GNUNET_JSON_spec_json ("providers_public_keys", + &json_ppk), + GNUNET_JSON_spec_fixed_auto ("pre_encryption_key", + &dc->pre_enc_key), + GNUNET_JSON_spec_json ("secret_shares", + &shares), + GNUNET_JSON_spec_uint8 ("expiration", + &dc->expiration), + GNUNET_JSON_spec_end () + }; + + res = TALER_MHD_parse_json_data (connection, + dc->json, + spec); + + if (GNUNET_SYSERR == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break (0); + return MHD_NO; + } + if (GNUNET_NO == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to parse request body"); + } + + /* check number of submitted provider public keys*/ + if (254 < json_array_size (json_ppk)) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Too many provider public keys"); + } + + /* set number of participants */ + dc->num_of_participants = json_array_size (json_ppk); + + /* validate provider_index, threshold and num_of_participants */ + if (GNUNET_OK != FROST_validate_dkg_params (dc->provider_index, + dc->threshold, + dc->num_of_participants)) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Protocol parameters out of bound"); + } + + /* Check if called id is matching the send data */ + if (GNUNET_OK != FROSIX_dkg_validate_request_id_ (&dc->request_id, + &dc->context_string, + &dc->auth_hash, + &dc->provider_salt, + dc->provider_index, + dc->num_of_participants, + dc->threshold)) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to validate request ID"); + } + + /* parse provider public keys */ + struct GNUNET_CRYPTO_EddsaPublicKey + providers_public_keys[dc->num_of_participants]; + for (unsigned int i = 0; i < dc->num_of_participants; i++) + { + struct GNUNET_JSON_Specification ppk_spec[] = { + GNUNET_JSON_spec_fixed_auto (NULL, + &providers_public_keys[i]), + GNUNET_JSON_spec_end () + }; + + res = TALER_MHD_parse_json_array (connection, + json_ppk, + ppk_spec, + i, + -1); + + if (GNUNET_SYSERR == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (ppk_spec); + GNUNET_break (0); + return MHD_NO; + } + if (GNUNET_NO == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (ppk_spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to parse request body"); + } + + GNUNET_JSON_parse_free (ppk_spec); + } + + /* check if there are 'num_of_participants - 1' shares */ + if (dc->num_of_participants - 1 != json_array_size (shares)) + { + GNUNET_break_op (0); + GNUNET_JSON_parse_free (spec); + + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Number of shares not matching"); + } + + share_n_comm_length = dc->num_of_participants - 1; + + /* initialize shares and commitments */ + struct FROST_DkgShare dkg_shares[dc->num_of_participants]; + struct FROST_DkgCommitment dkg_commitments[dc->num_of_participants]; + + { + /* parse all shares */ + struct FROSIX_EncryptedShareP enc_shares[share_n_comm_length]; + struct GNUNET_CRYPTO_EcdhePublicKey pub_enc_keys[share_n_comm_length]; + + unsigned int pi_counter = 0; + for (int i = 0; i < share_n_comm_length; i++) + { + if (dc->provider_index - 1 == pi_counter) + pi_counter++; + + struct GNUNET_JSON_Specification share_spec[] = { + GNUNET_JSON_spec_uint8 ("provider_index", + &dkg_shares[pi_counter].identifier), + GNUNET_JSON_spec_fixed_auto ("secret_share", + &enc_shares[i]), + GNUNET_JSON_spec_fixed_auto ("ephemeral_key", + &pub_enc_keys[i]), + GNUNET_JSON_spec_end () + }; + + res = TALER_MHD_parse_json_array (connection, + shares, + share_spec, + i, + -1); + + if (GNUNET_SYSERR == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (share_spec); + GNUNET_break (0); + return MHD_NO; + } + if (GNUNET_NO == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (share_spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to parse request body"); + } + + /* free json spec */ + GNUNET_JSON_parse_free (share_spec); + + pi_counter++; + } + + /* free json spec */ + GNUNET_JSON_parse_free (spec); + + /* get commitments from db */ + { + struct FROSIX_DkgCommitmentsRaw commits; + commits.length = (sizeof (dc->provider_index) + + (sizeof (struct FROST_Point) + * dc->threshold)) + * (share_n_comm_length); + + enum GNUNET_DB_QueryStatus qs; + qs = db->get_dkg_commitment (db->cls, + &dc->request_id, + &commits); + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "get_dkg_commitments"); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + + // FIXME: check how many bytes we got from the db + + /* parse result to struct */ + for (int i = 0; i < dc->num_of_participants; i++) + { + if (GNUNET_OK != FROST_initialize_dkg_commitment (&dkg_commitments[i], + dc->provider_index, + dc->threshold)) + { + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants); + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "Initialize DKG commitment"); + } + } + + unsigned int offset = 0; + unsigned int comm_counter = 0; + for (uint8_t i = 0; i < share_n_comm_length; i++) + { + if (dc->provider_index - 1 == comm_counter) + comm_counter++; + + memcpy (&dkg_commitments[comm_counter].identifier, + (char *) commits.ptr_commits + offset, + 1); + offset += 1; + + for (int j = 0; j < dc->threshold; j++) + { + memcpy (&dkg_commitments[comm_counter].share_comm[j].sc.xcoord, + (char *) commits.ptr_commits + offset, + sizeof (struct FROST_Point)); + offset += sizeof (struct FROST_Point); + } + + dkg_commitments[comm_counter].shares_commitments_length = dc->threshold; + + comm_counter++; + } + } + + + /* check if shares are valid */ + unsigned int share_counter = 0; + for (int i = 0; i < share_n_comm_length; i++) + { + if (dc->provider_index - 1 == i) + share_counter++; + + /* get key material */ + struct GNUNET_HashCode key_material; + if (GNUNET_OK != GNUNET_CRYPTO_eddsa_ecdh (&dc->priv_sig_key, + &pub_enc_keys[i], + &key_material)) + { + GNUNET_break_op (0); + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to compute encryption key"); + } + + /* derive key */ + struct GNUNET_CRYPTO_SymmetricSessionKey sym_key; + struct GNUNET_CRYPTO_SymmetricInitializationVector iv; + GNUNET_CRYPTO_hash_to_aes_key (&key_material, + &sym_key, + &iv); + + /* decrypt share */ + ssize_t len = GNUNET_CRYPTO_symmetric_decrypt (&enc_shares[i], + sizeof (enc_shares[i]), + &sym_key, + &iv, + &dkg_shares[share_counter]. + share); + + if ( -1 == len || sizeof (dkg_shares[share_counter].share) != len) + { + GNUNET_break_op (0); + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to decrypt encrypted share"); + } + + if (GNUNET_OK != FROST_keygen_validate_share ( + &dkg_commitments[share_counter], + &dkg_shares[share_counter], + dc->provider_index)) + { + GNUNET_break_op (0); + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to validate share"); + } + share_counter++; + } + } + + /* derive the final context string */ + struct FROST_DkgContextString cs_h; + if (GNUNET_YES != FROSIX_dkg_derive_context_string_ ( + &cs_h, + dc->provider_index, + dc->threshold, + &dc->context_string, + &dc->auth_hash, + providers_public_keys, + dc->num_of_participants, + &dc->secret_provider_salt)) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "Derive context string"); + } + + /* calculate own commitment and share */ + if (GNUNET_OK != FROSIX_dkg_commitment_generate_ ( + &dkg_commitments[dc->provider_index - 1], + &cs_h, + NULL, + dc->provider_index, + dc->threshold, + dc->num_of_participants)) + { + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants); + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "Generate DKG commitment"); + } + + struct FROST_DkgShare my_shares[dc->num_of_participants]; + if (GNUNET_OK != FROSIX_dkg_shares_generate_ ( + my_shares, + &cs_h, + NULL, + dc->provider_index, + dc->threshold, + dc->num_of_participants)) + { + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants); + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "Generate DKG shares"); + } + + /* calculate key share */ + struct FROST_KeyPair key_pair; + generate_key_pair (&key_pair, + dkg_shares, + my_shares, + dkg_commitments, + dc->provider_index, + dc->threshold, + dc->num_of_participants); + + /* free initialized memory */ + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants); + + /* Derive symmetric key */ + struct FROSIX_EncryptionKey encryption_key; + if (GNUNET_OK != derive_encryption_key (&encryption_key, + &dc->pre_enc_key, + &key_pair.group_pk, + &dc->provider_salt, + dc->provider_index)) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "Derive encryption key"); + } + + /* check if key is already stored */ + /* hash encryption key */ + struct FROST_HashCode enc_key_hash; + FROSIX_hash_encryption_key (&enc_key_hash, + &encryption_key); + + enum GNUNET_DB_QueryStatus qs; + qs = db->lookup_key (db->cls, + &enc_key_hash); + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_INVARIANT_FAILURE, + "lookup key"); + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + /* store key data */ + MHD_RESULT mhd_res; + mhd_res = store_key_data (dc, + &enc_key_hash, + &encryption_key, + &key_pair); + if (MHD_HTTP_OK != mhd_res) + { + return mhd_res; + } + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + // key is already stored - go ahead + break; + } + + // Sign data + struct FROSIX_DkgKeySignaturePS ks = { + .purpose.purpose = htonl (104), + .purpose.size = htonl (sizeof (ks)), + .public_key = key_pair.group_pk, + .auth_hash = dc->auth_hash, + }; + + struct GNUNET_CRYPTO_EddsaSignature sig; + GNUNET_CRYPTO_eddsa_sign (priv_sig_key, + &ks, + &sig); + + return TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_data_auto ("public_key", + &key_pair.group_pk), + GNUNET_JSON_pack_data_auto ("signature", + &sig)); +} +\ No newline at end of file diff --git a/src/backend/frosix-httpd_dkg-key_delete.c b/src/backend/frosix-httpd_dkg-key_delete.c @@ -0,0 +1,95 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_key.c + * @brief functions to handle incoming requests on /key + * @author Joel Urech + */ +#include "frosix-httpd_dkg.h" +#include "frosix-httpd.h" +#include "frosix-httpd_mhd.h" +#include "frosix_database_plugin.h" +#include <taler/taler_util.h> +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_db_lib.h> +#include "gnunet/gnunet_curl_lib.h" + +struct KeyDeleteContext +{ + /** + * Our handler context + */ + struct TM_HandlerContext *hc; + + /** + * Post parser context. + */ + void *post_ctx; + + /** + * Connection handle for closing or resuming + */ + struct MHD_Connection *connection; + + /** + * When should this request time out? + */ + struct GNUNET_TIME_Absolute timeout; +}; + + +MHD_RESULT +FH_handler_key_delete ( + struct MHD_Connection *connection, + struct TM_HandlerContext *hc, + const struct FROSIX_DkgRequestIdP *id) +{ + struct KeyDeleteContext *dc = hc->ctx; + + if (NULL == dc) + { + dc = GNUNET_new (struct KeyDeleteContext); + dc->connection = connection; + hc->ctx = dc; + } + + enum GNUNET_DB_QueryStatus qs; + qs = db->delete_key_data (db->cls, + &id->id); + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "key_delete"); + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + + struct FH_RequestHandler h204 = { + "", NULL, "text/html", + "<html><title>204: no content</title></html>", 0, + &TMH_MHD_handler_static_response, MHD_HTTP_NO_CONTENT + }; + + return TMH_MHD_handler_static_response (&h204, + connection); +} +\ No newline at end of file diff --git a/src/backend/frosix-httpd_dkg-shares.c b/src/backend/frosix-httpd_dkg-shares.c @@ -0,0 +1,668 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_dkg-shares.c + * @brief functions to handle incoming requests on /dkg-shares + * @author Joel Urech + */ +#include "frosix-httpd_dkg.h" +#include "frosix-httpd.h" +#include "frosix_database_plugin.h" +#include "frosix_service.h" +#include "keygen.h" +#include <taler/taler_util.h> +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_db_lib.h> + +struct DkgSharesContext +{ + /** + * + */ + uint8_t provider_index; + + /** + * + */ + uint8_t threshold; + + /** + * + */ + uint8_t num_of_participants; + + /** + * + */ + struct FROSIX_DkgContextStringP context_string; + + /** + * + */ + struct FROSIX_ChallengeHashP auth_hash; + + /** + * + */ + struct FROSIX_DkgRequestIdP request_id; + + /** + * + */ + struct FROSIX_ProviderSaltP provider_salt; + + /** + * + */ + struct FROSIX_SecretProviderSaltP secret_provider_salt; + + /** + * + */ + struct FROST_DkgCommitment *dkg_commitments; + + /** + * Our handler context + */ + struct TM_HandlerContext *hc; + + /** + * Uploaded JSON data, NULL if upload is not yet complete. + */ + json_t *json; + + /** + * Post parser context. + */ + void *post_ctx; + + /** + * Connection handle for closing or resuming + */ + struct MHD_Connection *connection; + + /** + * When should this request time out? + */ + struct GNUNET_TIME_Absolute timeout; +}; + +/** + * Return the generated dkg shares + * + * @param connection + * @param dkg_shares + * @return +*/ +static MHD_RESULT +return_dkg_shares ( + struct MHD_Connection *connection, + const struct FROST_DkgShare dkg_shares[], + const struct GNUNET_CRYPTO_EddsaPublicKey pub_keys[], + uint8_t provider_index, + uint8_t num_of_participants) +{ + // Prepare secret shares + json_t *shares; + shares = json_array (); + GNUNET_assert (NULL != shares); + int counter = 0; + + for (int i = 0; i < num_of_participants; i++) + { + if (provider_index - 1 != i) + { + uint8_t target = i + 1; + json_t *share; + share = json_object (); + + /* get key material */ + struct GNUNET_CRYPTO_EcdhePrivateKey priv_enc_key; + GNUNET_CRYPTO_ecdhe_key_create (&priv_enc_key); + + struct GNUNET_CRYPTO_EcdhePublicKey pub_enc_key; + GNUNET_CRYPTO_ecdhe_key_get_public (&priv_enc_key, + &pub_enc_key); + + struct GNUNET_HashCode key_material; + if (GNUNET_OK != GNUNET_CRYPTO_ecdh_eddsa (&priv_enc_key, + &pub_keys[counter], + &key_material)) + { + GNUNET_break (0); + return MHD_NO; + } + + /* derive key */ + struct GNUNET_CRYPTO_SymmetricSessionKey sym_key; + struct GNUNET_CRYPTO_SymmetricInitializationVector iv; + GNUNET_CRYPTO_hash_to_aes_key (&key_material, + &sym_key, + &iv); + + /* encrypt share */ + struct FROSIX_EncryptedShareP encrypted_share; + ssize_t len = GNUNET_CRYPTO_symmetric_encrypt (&dkg_shares[i].share, + sizeof (dkg_shares[i].share), + &sym_key, + &iv, + &encrypted_share); + + if (-1 == len || sizeof (encrypted_share) != len) + { + GNUNET_break (0); + return MHD_NO; + } + + /* pack data in json */ + share = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("target", + target), + GNUNET_JSON_pack_uint64 ("issuer", + provider_index), + GNUNET_JSON_pack_data_auto ("secret_share", + &encrypted_share), + GNUNET_JSON_pack_data_auto ("ephemeral_key", + &pub_enc_key) + ); + + GNUNET_assert (0 == + json_array_append ( + shares, + share)); + counter++; + } + } + + return TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_array_steal ("secret_shares", + shares)); +} + +static MHD_RESULT +store_commitments (struct DkgSharesContext *dc) +{ + /* copy commitments to a single byte array */ + struct FROSIX_DkgCommitmentsRaw commits; + commits.length = (sizeof (dc->provider_index) + + (sizeof (struct FROST_Point) + * dc->threshold)) + * (dc->num_of_participants - 1); + commits.ptr_commits = calloc (1, commits.length); + + unsigned int offset = 0; + + for (int i = 0; i < dc->num_of_participants - 1; i++) + { + memcpy ((char *) commits.ptr_commits + offset, + &dc->dkg_commitments[i].identifier, + 1); + offset += 1; + + for (int j = 0; j < dc->threshold; j++) + { + memcpy ((char *) commits.ptr_commits + offset, + &dc->dkg_commitments[i].share_comm[j].sc.xcoord, + sizeof (struct FROST_Point)); + offset += sizeof (struct FROST_Point); + } + } + + /* store commitments */ + enum GNUNET_DB_QueryStatus qs; + qs = db->store_dkg_commitment (db->cls, + &dc->request_id, + &commits); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_break (0); + free (commits.ptr_commits); + return TALER_MHD_reply_with_error (dc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_INVARIANT_FAILURE, + "store dkg-commitment"); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + + /* free initialized memory */ + free (commits.ptr_commits); + return MHD_HTTP_OK; +} + + +MHD_RESULT +FH_handler_dkg_shares_post ( + struct MHD_Connection *connection, + struct TM_HandlerContext *hc, + const struct FROSIX_DkgRequestIdP *dkg_id, + const struct FROSIX_ProviderSaltP *provider_salt, + const struct FROSIX_SecretProviderSaltP *secret_provider_salt, + const char *dkg_commitment_data, + size_t *dkg_commitment_data_size) +{ + enum GNUNET_GenericReturnValue res; + struct DkgSharesContext *dc = hc->ctx; + json_t *json_ppk = NULL; + json_t *commitments = NULL; + + if (NULL == dc) + { + dc = GNUNET_new (struct DkgSharesContext); + dc->connection = connection; + dc->request_id = *dkg_id; + dc->provider_salt = *provider_salt; + dc->secret_provider_salt = *secret_provider_salt; + hc->ctx = dc; + } + + /* parse request body */ + if (NULL == dc->json) + { + res = TALER_MHD_parse_post_json (dc->connection, + &dc->post_ctx, + dkg_commitment_data, + dkg_commitment_data_size, + &dc->json); + if (GNUNET_SYSERR == res) + { + GNUNET_break (0); + return MHD_NO; + } + if ((GNUNET_NO == res || + (NULL == dc->json))) + { + return MHD_YES; + } + } + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_uint8 ("provider_index", + &dc->provider_index), + GNUNET_JSON_spec_uint8 ("threshold", + &dc->threshold), + GNUNET_JSON_spec_fixed_auto ("context_string", + &dc->context_string), + GNUNET_JSON_spec_fixed_auto ("auth_hash", + &dc->auth_hash), + GNUNET_JSON_spec_json ("providers_public_keys", + &json_ppk), + GNUNET_JSON_spec_json ("dkg_commitments", + &commitments), + GNUNET_JSON_spec_end () + }; + + res = TALER_MHD_parse_json_data (connection, + dc->json, + spec); + + if (GNUNET_SYSERR == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break (0); + return MHD_NO; + } + if (GNUNET_NO == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to parse request body"); + } + + /* check number of submitted provider public keys*/ + if (254 < json_array_size (json_ppk)) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Too many provider public keys"); + } + + /* set number of participants */ + dc->num_of_participants = json_array_size (json_ppk); + + /* validate provider index, threshold and num_of_participants */ + if (GNUNET_OK != FROST_validate_dkg_params (dc->provider_index, + dc->threshold, + dc->num_of_participants)) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Protocol parameters out of bound"); + } + + /* Check if called id is matching the send data */ + if (GNUNET_OK != FROSIX_dkg_validate_request_id_ (&dc->request_id, + &dc->context_string, + &dc->auth_hash, + &dc->provider_salt, + dc->provider_index, + dc->num_of_participants, + dc->threshold)) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to validate request ID"); + } + + /* parse provider public keys */ + struct GNUNET_CRYPTO_EddsaPublicKey + providers_public_keys[dc->num_of_participants]; + for (unsigned int i = 0; i < dc->num_of_participants; i++) + { + struct GNUNET_JSON_Specification ppk_spec[] = { + GNUNET_JSON_spec_fixed_auto (NULL, + &providers_public_keys[i]), + GNUNET_JSON_spec_end () + }; + + res = TALER_MHD_parse_json_array (connection, + json_ppk, + ppk_spec, + i, + -1); + + if (GNUNET_SYSERR == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (ppk_spec); + GNUNET_break (0); + return MHD_NO; + } + if (GNUNET_NO == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (ppk_spec); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to parse request body"); + } + + GNUNET_JSON_parse_free (ppk_spec); + } + + /* check if there are num_of_participants - 1 commitments */ + if (dc->num_of_participants - 1 != json_array_size (commitments)) + { + GNUNET_break_op (0); + GNUNET_JSON_parse_free (spec); + + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Number of commitments not matching"); + } + + /* parse all commitments */ + struct FROST_DkgCommitment dkg_commitments[dc->num_of_participants - 1]; + dc->dkg_commitments = dkg_commitments; + json_t *coms = json_array (); + + // Place to store the delivered public keys to later encrypt our secret shares + // against + struct GNUNET_CRYPTO_EddsaPublicKey pub_sig_keys[dc->num_of_participants - 1]; + + for (unsigned int i = 0; i < dc->num_of_participants - 1; i++) + { + if (GNUNET_OK != FROST_initialize_dkg_commitment (&dc->dkg_commitments[i], + dc->provider_index, + dc->threshold)) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "Initialize DKG commitment"); + } + + json_t *json_temp = NULL; + struct GNUNET_JSON_Specification com_spec[] = { + GNUNET_JSON_spec_uint8 ("provider_index", + &dc->dkg_commitments[i].identifier), + GNUNET_JSON_spec_json ("dkg_commitment", + &json_temp), + GNUNET_JSON_spec_fixed_auto ("zkp_r", + &dc->dkg_commitments[i].zkp.r), + GNUNET_JSON_spec_fixed_auto ("zkp_z", + &dc->dkg_commitments[i].zkp.z), + GNUNET_JSON_spec_fixed_auto ("public_key", + &pub_sig_keys[i]), + GNUNET_JSON_spec_end () + }; + + res = TALER_MHD_parse_json_array (connection, + commitments, + com_spec, + i, + -1); + + if (GNUNET_SYSERR == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (com_spec); + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants - 1); + GNUNET_break (0); + return MHD_NO; + } + if (GNUNET_NO == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (com_spec); + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants - 1); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to parse request body"); + } + + /* check if there are `threshold` commitment values */ + if (dc->threshold != json_array_size (json_temp)) + { + GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (com_spec); + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants - 1); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Number of commitment values not equal to threshold value"); + } + dc->dkg_commitments[i].shares_commitments_length = dc->threshold; + + /* add temp value to json array */ + json_array_append_new (coms, + json_temp); + + /* parse the commitment values */ + for (unsigned int j = 0; j < dc->threshold; j++) + { + struct GNUNET_JSON_Specification coms_spec[] = { + GNUNET_JSON_spec_fixed_auto (NULL, + &dc->dkg_commitments[i].share_comm[j]), + GNUNET_JSON_spec_end () + }; + + res = TALER_MHD_parse_json_array (connection, + json_array_get (coms, + i), + coms_spec, + j, + -1); + + if (GNUNET_SYSERR == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (com_spec); + GNUNET_JSON_parse_free (coms_spec); + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants - 1); + GNUNET_break (0); + return MHD_NO; + } + if (GNUNET_NO == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (com_spec); + GNUNET_JSON_parse_free (coms_spec); + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants - 1); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to parse request body"); + } + + /* free json spec */ + GNUNET_JSON_parse_free (coms_spec); + } + + /* free json spec */ + GNUNET_JSON_parse_free (com_spec); + } + + /* free json spec */ + GNUNET_JSON_parse_free (spec); + + /* check if commitments are valid */ + for (unsigned int i = 0; i < dc->num_of_participants - 1; i++) + { + /* hash received pub key */ + struct FROST_HashState h_s; + struct FROST_HashCode pub_key_hash; + FROST_hash_init (&h_s); + FROST_hash_fixed_update (&h_s, + &pub_sig_keys[i].q_y, + sizeof (pub_sig_keys[i].q_y)); + FROST_hash_final (&h_s, + &pub_key_hash); + + if (GNUNET_OK != FROST_keygen_validate_commitment (&dc->dkg_commitments[i], + &pub_key_hash, + dc->num_of_participants)) + { + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants - 1); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Could not validate commitment"); + } + } + + /* check if commitments are already stored */ + enum GNUNET_DB_QueryStatus qs; + qs = db->lookup_dkg_commitment (db->cls, + &dc->request_id); + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants - 1); + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_INVARIANT_FAILURE, + "lookup dkg-commitment"); + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + /* store commitments */ + MHD_RESULT mhd_res; + mhd_res = store_commitments (dc); + if (MHD_HTTP_OK != mhd_res) + { + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants - 1); + return mhd_res; + } + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + // commitments are already stored - go ahead + break; + } + + FROST_free_dkg_commitment (dkg_commitments, + dc->num_of_participants - 1); + + /* derive the final context string */ + struct FROST_DkgContextString cs_h; + if (GNUNET_YES != FROSIX_dkg_derive_context_string_ ( + &cs_h, + dc->provider_index, + dc->threshold, + &dc->context_string, + &dc->auth_hash, + providers_public_keys, + dc->num_of_participants, + &dc->secret_provider_salt)) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "Derive context string"); + } + + /* create shares */ + struct FROST_DkgShare dkg_shares[dc->num_of_participants]; + + if (GNUNET_OK != FROSIX_dkg_shares_generate_ (dkg_shares, + &cs_h, + NULL, + dc->provider_index, + dc->threshold, + dc->num_of_participants)) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "Generate DKG shares"); + } + + res = return_dkg_shares (connection, + dkg_shares, + pub_sig_keys, + dc->provider_index, + dc->num_of_participants); + + return res; + +} +\ No newline at end of file diff --git a/src/backend/frosix-httpd_dkg.h b/src/backend/frosix-httpd_dkg.h @@ -0,0 +1,142 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_dkg.h + * @brief functions to handle incoming requests on /dkg-* + * @author Joel Urech + */ +#ifndef FROSIX_HTTPD_DKG_H +#define FROSIX_HTTPD_DKG_H +#include "frosix-httpd.h" +#include "keygen.h" +#include "frosix_service.h" +#include "frosix_util_lib.h" +#include <microhttpd.h> +#include <taler/taler_mhd_lib.h> + + +/** + * + * + * @param[out] dkg_comm + * @param[in] context_string + * @param[in] additional_data + * @param identifier + * @param threshold + * @param num_of_participants + * @return GNUNET_OK or GNUNET_NO +*/ +enum GNUNET_GenericReturnValue +FROSIX_dkg_commitment_generate_ ( + struct FROST_DkgCommitment *dkg_comm, + const struct FROST_DkgContextString *context_string, + const struct FROST_HashCode *additional_data, + uint8_t identifier, + uint8_t threshold, + uint8_t num_of_participants); + +/** + * FIXME +*/ +enum GNUNET_GenericReturnValue +FROSIX_dkg_shares_generate_ ( + struct FROST_DkgShare dkg_shares[], + const struct FROST_DkgContextString *context_string, + const struct FROST_HashCode *additional_data, + uint8_t identifier, + uint8_t threshold, + uint8_t num_of_participants); + +/** + * +*/ +enum GNUNET_GenericReturnValue +FROSIX_dkg_derive_context_string_ ( + struct FROST_DkgContextString *resulting_context_string, + uint8_t provider_index, + uint8_t threshold, + const struct FROSIX_DkgContextStringP *input_context_string, + const struct FROSIX_ChallengeHashP *auth_hash, + const struct GNUNET_CRYPTO_EddsaPublicKey provider_public_keys[], + size_t length, + const struct FROSIX_SecretProviderSaltP*secret_provider_salt); + + +/** + * +*/ +enum GNUNET_GenericReturnValue +FROSIX_dkg_validate_request_id_ ( + const struct FROSIX_DkgRequestIdP *request_id, + const struct FROSIX_DkgContextStringP *context_string, + const struct FROSIX_ChallengeHashP *auth_hash, + const struct FROSIX_ProviderSaltP *secret_provider_salt, + uint8_t identifier, + uint8_t num_of_participants, + uint8_t threshold); + +/** + * FIXME +*/ +MHD_RESULT +FH_handler_dkg_commitment_post ( + struct MHD_Connection *connection, + struct TM_HandlerContext *hc, + const struct FROSIX_DkgRequestIdP *dkg_id, + const struct FROSIX_ProviderSaltP *provider_salt, + const struct FROSIX_SecretProviderSaltP *secret_provider_salt, + const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_sig_key, + const struct GNUNET_CRYPTO_EddsaPublicKey *pub_sig_key, + const char *dkg_commitment_data, + size_t *dkg_commitment_data_size); + +/** + * FIXME +*/ +MHD_RESULT +FH_handler_dkg_shares_post ( + struct MHD_Connection *connection, + struct TM_HandlerContext *hc, + const struct FROSIX_DkgRequestIdP *dkg_id, + const struct FROSIX_ProviderSaltP *provider_salt, + const struct FROSIX_SecretProviderSaltP *secret_provider_salt, + const char *dkg_commitment_data, + size_t *dkg_commitment_data_size); + +/** + * FIXME +*/ +MHD_RESULT +FH_handler_dkg_key_post ( + struct MHD_Connection *connection, + struct TM_HandlerContext *hc, + const struct FROSIX_DkgRequestIdP *dkg_id, + const struct FROSIX_ProviderSaltP *provider_salt, + const struct FROSIX_SecretProviderSaltP *secret_provider_salt, + const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_sig_key, + const char *dkg_commitment_data, + size_t *dkg_commitment_data_size); + +/** + * FIXME +*/ +MHD_RESULT +FH_handler_key_delete ( + struct MHD_Connection *connection, + struct TM_HandlerContext *hc, + const struct FROSIX_DkgRequestIdP *id); + +#endif +\ No newline at end of file diff --git a/src/backend/frosix-httpd_mhd.c b/src/backend/frosix-httpd_mhd.c @@ -0,0 +1,54 @@ +/* + This file is part of Frosix + Copyright (C) 2014, 2015, 2016 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file frosix-httpd_mhd.c + * @brief helpers for MHD interaction; these are TALER_EXCHANGE_handler_ functions + * that generate simple MHD replies that do not require any real operations + * to be performed (error handling, static pages, etc.) + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#include "platform.h" +#include <jansson.h> +#include "frosix-httpd_mhd.h" + + +MHD_RESULT +TMH_MHD_handler_static_response (struct FH_RequestHandler *rh, + struct MHD_Connection *connection) +{ + if (0 == rh->data_size) + rh->data_size = strlen ((const char *) rh->data); + return TALER_MHD_reply_static (connection, + rh->response_code, + rh->mime_type, + (void *) rh->data, + rh->data_size); +} + + +MHD_RESULT +TMH_MHD_handler_agpl_redirect (struct FH_RequestHandler *rh, + struct MHD_Connection *connection) +{ + (void) rh; + return TALER_MHD_reply_agpl (connection, + "https://git.taler.net/anastasis.git"); +} + + +/* end of frosix-httpd_mhd.c */ diff --git a/src/backend/frosix-httpd_mhd.h b/src/backend/frosix-httpd_mhd.h @@ -0,0 +1,56 @@ +/* + This file is part of Frosix + Copyright (C) 2014, 2015 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file frosix-httpd_mhd.h + * @brief helpers for MHD interaction, used to generate simple responses + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#ifndef FROSIX_HTTPD_MHD_H +#define FROSIX_HTTPD_MHD_H +#include <gnunet/gnunet_util_lib.h> +#include <microhttpd.h> +#include "frosix-httpd.h" + + +/** + * Function to call to handle the request by sending + * back static data from the @a rh. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @return MHD result code + */ +MHD_RESULT +TMH_MHD_handler_static_response (struct FH_RequestHandler *rh, + struct MHD_Connection *connection); + + +/** + * Function to call to handle the request by sending + * back a redirect to the AGPL source code. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @return MHD result code + */ +MHD_RESULT +TMH_MHD_handler_agpl_redirect (struct FH_RequestHandler *rh, + struct MHD_Connection *connection); + + +#endif diff --git a/src/backend/frosix-httpd_seed.c b/src/backend/frosix-httpd_seed.c @@ -0,0 +1,67 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_get.c + * @brief functions to handle incoming requests on /seed + * @author Joel Urech + */ +#include "frosix-httpd_seed.h" +#include "frosix-httpd.h" +#include <sodium.h> + +struct FROSIX_RndBytes +{ + uint8_t bytes[FROSIX_SEED_SIZE]; +}; + +/** + * @brief Wraps libsodium to get rnd bytes. + * The amount of bytes is defined in the global FROSIX_SEED_SIZE + * + * @param[out] rnd_bytes Pointer to the struct to fill with rnd bytes. +*/ +static void +get_rnd_bytes (struct FROSIX_RndBytes *rnd_bytes) +{ + randombytes_buf (rnd_bytes->bytes, FROSIX_SEED_SIZE); +} + + +MHD_RESULT +FH_seed_get (struct FH_RequestHandler *rh, + struct MHD_Connection *connection) +{ + struct MHD_Response *resp; + MHD_RESULT ret; + struct FROSIX_RndBytes *rnd_bytes; + + rnd_bytes = calloc (1, FROSIX_SEED_SIZE); + if (NULL == rnd_bytes) + return MHD_NO; + + get_rnd_bytes (rnd_bytes); + + resp = MHD_create_response_from_buffer (FROSIX_SEED_SIZE, + rnd_bytes, + MHD_RESPMEM_MUST_FREE); + + TALER_MHD_add_global_headers (resp); + ret = MHD_queue_response (connection, + MHD_HTTP_OK, + resp); + MHD_destroy_response (resp); + return ret; +} +\ No newline at end of file diff --git a/src/backend/frosix-httpd_seed.h b/src/backend/frosix-httpd_seed.h @@ -0,0 +1,39 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_seed.h + * @brief function to handle incoming requests on /policy + * @author Joel Urech + */ +#ifndef FROSIX_HTTPD_SEED_H +#define FROSIX_HTTPD_SEED_H +#include "frosix-httpd.h" +#include <microhttpd.h> + +#define FROSIX_SEED_SIZE 64 + +/** + * Manages a /seed call. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @return MHD result code + */ +MHD_RESULT +FH_seed_get (struct FH_RequestHandler *rh, + struct MHD_Connection *connection); + +#endif +\ No newline at end of file diff --git a/src/backend/frosix-httpd_sig-commitment.c b/src/backend/frosix-httpd_sig-commitment.c @@ -0,0 +1,572 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_sign-commitment.c + * @brief functions to handle incoming requests on /sign-commitment + * @author Joel Urech + */ +#include "frosix-httpd_sig.h" +#include "frosix-httpd.h" +#include "frosix_database_plugin.h" +#include "frost_high.h" +#include "frost_low.h" +#include <taler/taler_util.h> +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_db_lib.h> +#include "frosix_authorization_plugin.h" + +/** + * What is the maximum frequency at which we allow + * clients to attempt to answer security questions? + */ +#define MAX_QUESTION_FREQ GNUNET_TIME_relative_multiply ( \ + GNUNET_TIME_UNIT_SECONDS, 30) + +/** + * How many retries do we allow per code? + */ +#define INITIAL_RETRY_COUNTER 3 + +struct SignCommitmentContext +{ + /** + * + */ + uint32_t identifier; + + /** + * + */ + struct FROST_HashCode enc_key_hash; + + /** + * + */ + struct FROST_MessageHash message_hash; + + /** + * + */ + const char *auth_method; + + /** + * + */ + struct GNUNET_HashCode auth_data; + + /** + * + */ + bool auth_data_parsed; + + /** + * + */ + struct GNUNET_CRYPTO_Edx25519Signature auth_sig; + + /** + * + */ + bool auth_sig_parsed; + + /** + * + */ + struct GNUNET_CRYPTO_Edx25519PublicKey auth_pub; + + /** + * + */ + bool auth_pub_parsed; + + /** + * + */ + struct FROSIX_SigRequestIdP id; + + /** + * Reference to the authorization plugin which was loaded + */ + struct FROSIX_AuthorizationPlugin *authorization; + + + /** + * Our handler context + */ + struct TM_HandlerContext *hc; + + /** + * Uploaded JSON data, NULL if upload is not yet complete. + */ + json_t *json; + + /** + * Post parser context. + */ + void *post_ctx; + + /** + * Connection handle for closing or resuming + */ + struct MHD_Connection *connection; +}; + + +static MHD_RESULT +return_sig_commitment (struct SignCommitmentContext *dc, + struct MHD_Connection *connection) +{ + /* generate random seed */ + struct FROST_CommitmentSeed seed; + FROST_get_random_seed (&seed); + + /* compute commitments */ + struct FROST_Nonce com_nonce; + struct FROST_Commitment commitment; + FROST_generate_nonce_and_commitment (&com_nonce, + &commitment, + &dc->message_hash, + &seed); + + /* compute commitment_id for storing in db */ + struct GNUNET_HashCode db_id; + FROSIX_compute_db_commitment_id (&db_id, + &dc->enc_key_hash, + &commitment); + + /* store seed in db */ + enum GNUNET_DB_QueryStatus qs; + qs = db->store_commitment_seed (db->cls, + &db_id, + &seed); + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_break (0); + return TALER_MHD_reply_with_error (dc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_INVARIANT_FAILURE, + "store commitment seed"); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + + /* parse commitments to json */ + return TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_data_auto ("hiding_commitment", + &commitment.hiding_commitment), + GNUNET_JSON_pack_data_auto ("binding_commitment", + &commitment.binding_commitment)); +} + + +/** + * Generate a response telling the client that answering this + * challenge failed because the rate limit has been exceeded. + * + * @param gc request to answer for + * @return MHD status code + */ +static MHD_RESULT +reply_rate_limited (const struct SignCommitmentContext *gc) +{ + if (NULL != gc->authorization) + return TALER_MHD_REPLY_JSON_PACK ( + gc->connection, + MHD_HTTP_TOO_MANY_REQUESTS, + TALER_MHD_PACK_EC (TALER_EC_GENERIC_TIMEOUT), + GNUNET_JSON_pack_uint64 ("request_limit", + gc->authorization->retry_counter), + GNUNET_JSON_pack_time_rel ("request_frequency", + gc->authorization->code_rotation_period)); + /* must be security question */ + return TALER_MHD_REPLY_JSON_PACK ( + gc->connection, + MHD_HTTP_TOO_MANY_REQUESTS, + TALER_MHD_PACK_EC (TALER_EC_GENERIC_TIMEOUT), + GNUNET_JSON_pack_uint64 ("request_limit", + INITIAL_RETRY_COUNTER), + GNUNET_JSON_pack_time_rel ("request_frequency", + MAX_QUESTION_FREQ)); +} + + +/** + * Use the database to rate-limit queries to the authentication + * procedure, but without actually storing 'real' challenge codes. + * + * @param[in,out] gc context to rate limit requests for + * @return #GNUNET_OK if rate-limiting passes, + * #GNUNET_NO if a reply was sent (rate limited) + * #GNUNET_SYSERR if we failed and no reply + * was queued + */ +static enum GNUNET_GenericReturnValue +rate_limit (struct SignCommitmentContext *gc) +{ + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_TIME_Timestamp rt; + uint64_t code; + enum FROSIX_DB_CodeStatus cs; + bool satisfied; + uint64_t dummy; + + struct FROSIX_ChallengeIdP challenge_id; + GNUNET_CRYPTO_hash (&gc->id, + sizeof (gc->id), + &challenge_id.hash); + + rt = GNUNET_TIME_UNIT_FOREVER_TS; + qs = db->create_challenge_code (db->cls, + &challenge_id, + MAX_QUESTION_FREQ, + GNUNET_TIME_UNIT_HOURS, + INITIAL_RETRY_COUNTER, + &rt, + &code); + if (0 > qs) + { + GNUNET_break (0 < qs); + return (MHD_YES == + TALER_MHD_reply_with_error (gc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "create_challenge_code (for rate limiting)")) + ? GNUNET_NO + : GNUNET_SYSERR; + } + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + { + return (MHD_YES == + reply_rate_limited (gc)) + ? GNUNET_NO + : GNUNET_SYSERR; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Using intentionally wrong answer to produce rate-limiting\n"); + /* decrement trial counter */ + cs = db->verify_challenge_code (db->cls, + &challenge_id, + &challenge_id.hash, /* always use wrong answer + */ + &dummy, + &satisfied); + switch (cs) + { + case FROSIX_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH: + /* good, what we wanted */ + return GNUNET_OK; + case FROSIX_DB_CODE_STATUS_HARD_ERROR: + case FROSIX_DB_CODE_STATUS_SOFT_ERROR: + GNUNET_break (0); + return (MHD_YES == + TALER_MHD_reply_with_error (gc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "verify_challenge_code")) + ? GNUNET_NO + : GNUNET_SYSERR; + case FROSIX_DB_CODE_STATUS_NO_RESULTS: + return (MHD_YES == + reply_rate_limited (gc)) + ? GNUNET_NO + : GNUNET_SYSERR; + case FROSIX_DB_CODE_STATUS_VALID_CODE_STORED: + /* this should be impossible, we used code+1 */ + GNUNET_assert (0); + } + return GNUNET_SYSERR; +} + + +/** + * Handle special case of a security question where we do not + * generate a code. Rate limits answers against brute forcing. + * + * @param[in,out] gc request to handle + * @param decrypted_truth hash to check against + * @param decrypted_truth_size number of bytes in @a decrypted_truth + * @return MHD status code + */ +static MHD_RESULT +handle_security_question (struct SignCommitmentContext *gc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Handling security question challenge\n"); + /* rate limit */ + /*{ + enum GNUNET_GenericReturnValue ret; + + ret = rate_limit (gc); + if (GNUNET_OK != ret) + return (GNUNET_NO == ret) ? MHD_YES : MHD_NO; + }*/ + /* check reply matches truth */ + /* get auth data from DB */ + struct FROSIX_ChallengeHashP auth_hash; + + enum GNUNET_DB_QueryStatus qs; + qs = db->get_auth_hash (db->cls, + &gc->enc_key_hash, + &auth_hash); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_break (0); + /* FROSIX_EC_KEY_NOT_FOUND */ + return TALER_MHD_reply_with_error (gc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "auth_data_select"); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + + /* check if hash of submitted public key matches our stored hash */ + struct GNUNET_HashCode db_auth_answer; + struct GNUNET_HashContext *hc = GNUNET_CRYPTO_hash_context_start (); + GNUNET_CRYPTO_hash_context_read (hc, + &gc->auth_pub, + sizeof (gc->auth_pub)); + GNUNET_CRYPTO_hash_context_read (hc, + "FROSIX", + strlen ("FROSIX")); + GNUNET_CRYPTO_hash_context_finish (hc, + &db_auth_answer); + + if (GNUNET_OK != FROSIX_gnunet_hash_cmp (&db_auth_answer, + &auth_hash.hash)) + { + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Authentication public key not matching\n"); + return TALER_MHD_reply_with_error (gc->connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_GENERIC_INVALID_RESPONSE, + NULL); + } + + /* check signature of message hash with submitted public key */ + struct FROSIX_AuthSignaturePS as = { + .purpose.purpose = htonl (72), + .purpose.size = htonl (sizeof (as)), + .mh = gc->message_hash, + }; + + if (GNUNET_OK != GNUNET_CRYPTO_edx25519_verify (72, + &as, + &gc->auth_sig, + &gc->auth_pub)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Signature of message not verified\n"); + return TALER_MHD_reply_with_error (gc->connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_GENERIC_INVALID_RESPONSE, + NULL); + } + + /* good, return the key share */ + return return_sig_commitment (gc, + gc->connection); +} + + +MHD_RESULT +FH_handler_sig_commitment_post ( + struct MHD_Connection *connection, + struct TM_HandlerContext *hc, + const struct FROSIX_SigRequestIdP *id, + const char *sign_commitment_data, + size_t *sign_commitment_data_size) +{ + enum GNUNET_GenericReturnValue res; + struct SignCommitmentContext *dc = hc->ctx; + + if (NULL == dc) + { + dc = GNUNET_new (struct SignCommitmentContext); + dc->connection = connection; + dc->id = *id; + hc->ctx = dc; + } + + /* parse request body */ + if (NULL == dc->json) + { + res = TALER_MHD_parse_post_json (dc->connection, + &dc->post_ctx, + sign_commitment_data, + sign_commitment_data_size, + &dc->json); + if (GNUNET_SYSERR == res) + { + GNUNET_break (0); + return MHD_NO; + } + if ((GNUNET_NO == res || + (NULL == dc->json))) + { + return MHD_YES; + } + } + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("message_hash", + &dc->message_hash), + GNUNET_JSON_spec_fixed_auto ("encryption_key_hash", + &dc->enc_key_hash), + GNUNET_JSON_spec_string ("auth_method", + &dc->auth_method), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_fixed_auto ("auth_data", + &dc->auth_data), + &dc->auth_data_parsed), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_fixed_auto ("auth_sig", + &dc->auth_sig), + &dc->auth_sig_parsed), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_fixed_auto ("auth_pub", + &dc->auth_pub), + &dc->auth_pub_parsed), + GNUNET_JSON_spec_end () + }; + + res = TALER_MHD_parse_json_data (connection, + dc->json, + spec); + + if (GNUNET_SYSERR == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break (0); + return MHD_NO; + } + if (GNUNET_NO == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break_op (0); + /* FROSIX_EC_PARAMETER_MALFORMED */ + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to parse request body"); + } + + GNUNET_JSON_parse_free (spec); + + /* validate id */ + { + struct FROSIX_SigRequestIdP req_id; + FROSIX_compute_signature_request_id (&req_id, + &dc->enc_key_hash, + &dc->message_hash); + if (GNUNET_NO == FROST_hash_cmp (&req_id.id, + &id->id)) + { + GNUNET_JSON_parse_free (spec); + /* FROSIX_EC_REQUEST_ID_NOT_MATCHING */ + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "ID in URL not matching data in body"); + } + } + + /* authenticate */ + if (0 == strcmp ("question", + dc->auth_method)) + { + if (&dc->auth_sig_parsed && &dc->auth_pub_parsed) + { + return handle_security_question (dc); + } + else + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + NULL); + } + } + else + { + if (! &dc->auth_data_parsed) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + NULL); + } + + enum FROSIX_DB_CodeStatus cs; + bool satisfied = false; + uint64_t code; + + struct FROSIX_ChallengeIdP challenge_id; + FROSIX_compute_challenge_id (&challenge_id, + &dc->enc_key_hash, + &dc->message_hash); + + /* random code, check against database */ + cs = db->verify_challenge_code (db->cls, + &challenge_id, + &dc->auth_data, + &code, + &satisfied); + switch (cs) + { + case FROSIX_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Provided response does not match our stored challenge\n"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_GENERIC_DB_FETCH_FAILED, + NULL); + case FROSIX_DB_CODE_STATUS_HARD_ERROR: + case FROSIX_DB_CODE_STATUS_SOFT_ERROR: + GNUNET_break (0); + return TALER_MHD_reply_with_error (dc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "verify_challenge_code"); + case FROSIX_DB_CODE_STATUS_NO_RESULTS: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Specified challenge code %s was not issued\n", + GNUNET_h2s (&dc->auth_data)); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "specific challenge code was not issued"); + case FROSIX_DB_CODE_STATUS_VALID_CODE_STORED: + return return_sig_commitment (dc, + connection); + default: + GNUNET_break (0); + return MHD_NO; + } + } +} +\ No newline at end of file diff --git a/src/backend/frosix-httpd_sig-share.c b/src/backend/frosix-httpd_sig-share.c @@ -0,0 +1,446 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_sign-share.c + * @brief functions to handle incoming requests on /sign-share + * @author Joel Urech + */ +#include "frosix-httpd_sig.h" +#include "frosix-httpd.h" +#include "frosix_database_plugin.h" +#include "frost_high.h" +#include "frost_verify.h" +#include <taler/taler_util.h> +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_db_lib.h> +#include "frosix_authorization_plugin.h" + +/** + * What is the maximum frequency at which we allow + * clients to attempt to answer security questions? + */ +#define MAX_QUESTION_FREQ GNUNET_TIME_relative_multiply ( \ + GNUNET_TIME_UNIT_SECONDS, 30) + +/** + * How many retries do we allow per code? + */ +#define INITIAL_RETRY_COUNTER 3 + +struct SignShareContext +{ + /** + * + */ + uint32_t identifier; + + /** + * + */ + uint8_t threshold; + + /** + * + */ + struct FROST_Commitment *commitments; + + /** + * + */ + struct FROSIX_EncryptionKey encryption_key; + + + /** + * + */ + struct FROST_HashCode enc_key_hash; + + /** + * + */ + struct FROST_MessageHash message_hash; + + /** + * + */ + struct FROSIX_SigRequestIdP id; + + /** + * Our handler context + */ + struct TM_HandlerContext *hc; + + /** + * Uploaded JSON data, NULL if upload is not yet complete. + */ + json_t *json; + + /** + * Post parser context. + */ + void *post_ctx; + + /** + * Connection handle for closing or resuming + */ + struct MHD_Connection *connection; +}; + + +/** + * FIXME +*/ +static struct FROST_Commitment * +get_my_commitment (uint32_t identifier, + struct FROST_Commitment commitments[], + uint8_t len) +{ + for (unsigned int i = 0; i < len; i++) + { + if (identifier == commitments[i].identifier) + return &commitments[i]; + } + return NULL; +} + + +static MHD_RESULT +return_sig_share (struct SignShareContext *gc) +{ + /* get key data from DB */ + struct FROSIX_EncryptionNonceP nonce; + struct FROSIX_KeyDataEncrypted enc_key_data; + + enum GNUNET_DB_QueryStatus qs_key; + qs_key = db->get_key_data (db->cls, + &gc->enc_key_hash, + &gc->identifier, + &nonce, + &enc_key_data); + + switch (qs_key) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_free (gc->commitments); + GNUNET_break (0); + /* FROSIX_EC_KEY_NOT_FOUND */ + return TALER_MHD_reply_with_error (gc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "key_data_select"); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + + /* validate identifier from db */ + if (gc->identifier <= 0 || gc->identifier >= 255 ) + { + GNUNET_free (gc->commitments); + GNUNET_break_op (0); + /* FROSIX_EC_KEY_DATA_CORRUPT */ + return TALER_MHD_reply_with_error (gc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Got invalid data from DB"); + } + + /* get commitment */ + struct FROST_Commitment *my_comm = get_my_commitment (gc->identifier, + gc->commitments, + gc->threshold); + + if (NULL == my_comm) + { + GNUNET_free (gc->commitments); + GNUNET_break_op (0); + /* FROSIX_COMMITMENT NOT_FOUND */ + return TALER_MHD_reply_with_error (gc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Commitment not found"); + } + + /* compute seed id in db */ + struct GNUNET_HashCode db_seed_id; + FROSIX_compute_db_commitment_id (&db_seed_id, + &gc->enc_key_hash, + my_comm); + + /* get commitment seed from DB */ + struct FROST_CommitmentSeed seed; + + enum GNUNET_DB_QueryStatus qs_seed; + qs_seed = db->get_and_delete_commitment_seed (db->cls, + &db_seed_id, + &seed); + + switch (qs_seed) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_free (gc->commitments); + GNUNET_break (0); + /* FROSIX_COMMITMENT_NOT_FOUND */ + return TALER_MHD_reply_with_error (gc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "get_commitment_seed"); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + + /* compute nonce and commitment */ + struct FROST_Nonce com_nonce; + struct FROST_Commitment commitment; + FROST_generate_nonce_and_commitment (&com_nonce, + &commitment, + &gc->message_hash, + &seed); + + /* FIXME check if computed commitment equals send commitment */ + + /* decrypt key data from db */ + struct FROSIX_KeyDataRaw decrypted; + if (GNUNET_OK != FROSIX_secretbox_keydata_open (&decrypted, + &enc_key_data, + &nonce, + &gc->encryption_key)) + { + GNUNET_free (gc->commitments); + GNUNET_break_op (0); + /* FROSIX_EC_DECRYPTION_FAILED */ + return TALER_MHD_reply_with_error (gc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to decrypt data from DB"); + } + + /* create key pair */ + struct FROST_KeyPair key_pair; + key_pair.identifier = gc->identifier; + + FROSIX_raw_key_to_struct (&key_pair, + &decrypted); + + /* compute signature share */ + struct FROST_SignatureShare sig_share; + FROST_sign_message_hash (&sig_share, + &gc->message_hash, + gc->commitments, + gc->threshold, + &key_pair, + &com_nonce); + + GNUNET_free (gc->commitments); + + return TALER_MHD_REPLY_JSON_PACK ( + gc->connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_data_auto ("signature_share", + &sig_share.sig_share), + GNUNET_JSON_pack_data_auto ("public_key_share", + &sig_share.pk_i)); +} + + +MHD_RESULT +FH_handler_sig_share_post ( + struct MHD_Connection *connection, + struct TM_HandlerContext *hc, + const struct FROSIX_SigRequestIdP *id, + const char *sign_share_data, + size_t *sign_share_data_size) +{ + enum GNUNET_GenericReturnValue res; + struct SignShareContext *dc = hc->ctx; + json_t *json_commitments = NULL; + + if (NULL == dc) + { + dc = GNUNET_new (struct SignShareContext); + dc->connection = connection; + dc->id = *id; + hc->ctx = dc; + } + + /* parse request body */ + if (NULL == dc->json) + { + res = TALER_MHD_parse_post_json (dc->connection, + &dc->post_ctx, + sign_share_data, + sign_share_data_size, + &dc->json); + if (GNUNET_SYSERR == res) + { + GNUNET_break (0); + return MHD_NO; + } + if ((GNUNET_NO == res || + (NULL == dc->json))) + { + return MHD_YES; + } + } + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("message_hash", + &dc->message_hash), + GNUNET_JSON_spec_fixed_auto ("encryption_key", + &dc->encryption_key), + GNUNET_JSON_spec_json ("commitments", + &json_commitments), + GNUNET_JSON_spec_end () + }; + + res = TALER_MHD_parse_json_data (connection, + dc->json, + spec); + + if (GNUNET_SYSERR == res) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break (0); + return MHD_NO; + } + if (GNUNET_NO == res) + { + GNUNET_JSON_parse_free (spec); + /* FROSIX_EC_PARAMETER_MALFORMED */ + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to parse request body"); + } + + /* hash encryption key */ + FROSIX_hash_encryption_key (&dc->enc_key_hash, + &dc->encryption_key); + + /* validate id */ + { + struct FROSIX_SigRequestIdP req_id; + FROSIX_compute_signature_request_id (&req_id, + &dc->enc_key_hash, + &dc->message_hash); + if (GNUNET_NO == FROST_hash_cmp (&req_id.id, + &id->id)) + { + GNUNET_JSON_parse_free (spec); + /* FROSIX_EC_REQUEST_ID_NOT_MATCHING */ + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "ID in URL not matching data in body"); + } + } + + /* get number of provided commitments */ + dc->threshold = json_array_size (json_commitments); + if (0 >= dc->threshold || dc->threshold >= 253) + { + GNUNET_JSON_parse_free (spec); + GNUNET_break_op (0); + /* FROSIX_EC_NO_OR_TOO_MANY_COMMITMENTS */ + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "No or too many commitments"); + } + + /* parse commitments */ + dc->commitments = GNUNET_new_array (dc->threshold, + struct FROST_Commitment); + + for (int i = 0; i < dc->threshold; i++) + { + struct GNUNET_JSON_Specification comm_spec[] = { + GNUNET_JSON_spec_uint8 ("identifier", + &dc->commitments[i].identifier), + GNUNET_JSON_spec_fixed_auto ("hiding_commitment", + &dc->commitments[i].hiding_commitment), + GNUNET_JSON_spec_fixed_auto ("binding_commitment", + &dc->commitments[i].binding_commitment), + GNUNET_JSON_spec_end () + }; + + res = TALER_MHD_parse_json_array (connection, + json_commitments, + comm_spec, + i, + -1); + + if (GNUNET_SYSERR == res) + { + GNUNET_free (dc->commitments); + GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (comm_spec); + GNUNET_break (0); + return MHD_NO; + } + if (GNUNET_NO == res) + { + GNUNET_free (dc->commitments); + GNUNET_JSON_parse_free (spec); + GNUNET_JSON_parse_free (comm_spec); + GNUNET_break_op (0); + /* FROSIX_EC_COMMITMENTS_MALFORMED */ + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to parse request body"); + } + + GNUNET_JSON_parse_free (comm_spec); + } + + GNUNET_JSON_parse_free (spec); + + /* validate commitments */ + for (unsigned int i = 0; i < dc->threshold; i++) + { + if (dc->commitments[i].identifier <= 0 || dc->commitments[i].identifier >= + 255 ) + { + GNUNET_free (dc->commitments); + GNUNET_break_op (0); + /* FROSIX_EC_COMMITMENT_IDENTIFIER_WRONG */ + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to validate commitments"); + } + + if (GNUNET_OK != FROST_validate_commitment (&dc->commitments[i])) + { + GNUNET_free (dc->commitments); + GNUNET_break_op (0); + /* FROSIX_EC_COMMITMENT_VALIDATION_FAILED (return id of failing + commitment?) */ + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Unable to validate commitments"); + } + } + + return return_sig_share (dc); +} +\ No newline at end of file diff --git a/src/backend/frosix-httpd_sig.h b/src/backend/frosix-httpd_sig.h @@ -0,0 +1,64 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_sign.h + * @brief functions to handle incoming requests on /sign-* + * @author Joel Urech + */ +#ifndef FROSIX_HTTPD_SIGN_H +#define FROSIX_HTTPD_SIGN_H +#include "frosix-httpd.h" +#include "keygen.h" +#include "frosix_util_lib.h" +#include "frosix_crypto.h" +#include <microhttpd.h> +#include <taler/taler_mhd_lib.h> + +MHD_RESULT +FH_handler_sig_commitment_post ( + struct MHD_Connection *connection, + struct TM_HandlerContext *hc, + const struct FROSIX_SigRequestIdP *id, + const char *sign_commitment_data, + size_t *sign_commitment_data_size); + + +MHD_RESULT +FH_handler_sig_share_post ( + struct MHD_Connection *connection, + struct TM_HandlerContext *hc, + const struct FROSIX_SigRequestIdP *id, + const char *sign_share_data, + size_t *sign_share_data_size); + + +/** + * FIXME +*/ +void +FROSIX_raw_key_to_struct (struct FROST_KeyPair *key_pair, + const struct FROSIX_KeyDataRaw *decrypted); + + +/** + * FIXME +*/ +void +FROSIX_compute_db_commitment_id (struct GNUNET_HashCode *db_id, + const struct FROST_HashCode *enc_key_hash, + const struct FROST_Commitment *commitment); + +#endif +\ No newline at end of file diff --git a/src/backend/frosix-httpd_terms.c b/src/backend/frosix-httpd_terms.c @@ -0,0 +1,79 @@ +/* + This file is part of Frosix + Copyright (C) 2020 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_terms.c + * @brief headers for /terms handler + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + */ +#include "platform.h" +#include "frosix-httpd_terms.h" +#include <taler/taler_json_lib.h> + +/** + * Our terms of service. + */ +static struct TALER_MHD_Legal *tos; + + +/** + * Our privacy policy. + */ +static struct TALER_MHD_Legal *pp; + + +MHD_RESULT +FH_handler_terms (struct FH_RequestHandler *rh, + struct MHD_Connection *connection) +{ + (void) rh; + return TALER_MHD_reply_legal (connection, + tos); +} + + +MHD_RESULT +FH_handler_privacy (struct FH_RequestHandler *rh, + struct MHD_Connection *connection) +{ + (void) rh; + return TALER_MHD_reply_legal (connection, + pp); +} + + +void +FH_load_terms (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + tos = TALER_MHD_legal_load (cfg, + "frosix", + "TERMS_DIR", + "TERMS_ETAG"); + if (NULL == tos) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Terms of service not configured\n"); + pp = TALER_MHD_legal_load (cfg, + "frosix", + "PRIVACY_DIR", + "PRIVACY_ETAG"); + if (NULL == pp) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Privacy policy not configured\n"); +} + + +/* end of frosix-httpd_terms.c */ diff --git a/src/backend/frosix-httpd_terms.h b/src/backend/frosix-httpd_terms.h @@ -0,0 +1,62 @@ +/* + This file is part of Frosix + Copyright (C) 2020, 2021 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file backend/frosix-httpd_terms.h + * @brief headers for /terms handler + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + */ +#ifndef FROSIX_HTTPD_TERMS_H +#define FROSIX_HTTPD_TERMS_H +#include <microhttpd.h> +#include "frosix-httpd.h" + +/** + * Manages a /terms call. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @return MHD result code + */ +MHD_RESULT +FH_handler_terms (struct FH_RequestHandler *rh, + struct MHD_Connection *connection); + + +/** + * Handle a "/privacy" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @return MHD result code + */ +MHD_RESULT +FH_handler_privacy (struct FH_RequestHandler *rh, + struct MHD_Connection *connection); + +/** + * Load our terms of service as per configuration. + * + * @param cfg configuration to process + */ +void +FH_load_terms (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +#endif + +/* end of frosix-httpd_terms.h */ diff --git a/src/backend/frosix.conf b/src/backend/frosix.conf @@ -0,0 +1,94 @@ +# This file is in the public domain. + +# These are default/sample settings for a merchant backend. + + +# General settings for the backend. +[frosix] + +# Use TCP or UNIX domain sockets? +SERVE = tcp + +# Which HTTP port does the backend listen on? Only used if "SERVE" is 'tcp'. +PORT = 9977 + +# Which IP address should we bind to? i.e. 127.0.0.1 or ::1 for loopback. +# Can also be given as a hostname. We will bind to the wildcard (dual-stack) +# if left empty. Only used if "SERVE" is 'tcp'. +# BIND_TO = + + +# Which unix domain path should we bind to? Only used if "SERVE" is 'unix'. +UNIXPATH = ${FROSIX_RUNTIME_DIR}/httpd/frosix-http.sock +# What should be the file access permissions (see chmod) for "UNIXPATH"? +UNIXPATH_MODE = 660 + +# Which database backend do we use? +DB = postgres + +# Display name of the business running this anastasis provider. +BUSINESS_NAME = FROSIX + +# Annual fee for an account +ANNUAL_FEE = TESTKUDOS:0.1 + +# Number of policy uploads included in one annual fee payment +#ANNUAL_POLICY_UPLOAD_LIMIT = 64 + +# Insurance +INSURANCE = TESTKUDOS:1.0 + +# Fee for one upload. +#TRUTH_UPLOAD_FEE = TESTKUDOS:0.1 + +# Fee for the creation of one signature +SIGNATURE_CREATION_FEE = TESTKUDOS:0.1 + +# Upload limit per backup, in megabytes +#UPLOAD_LIMIT_MB = 16 + +# Fulfillment URL of the ANASTASIS service itself. +FULFILLMENT_URL = taler://fulfillment-success + +# Server salt 16 Byte +PROVIDER_SALT = gUfO1KGOKYIFlFQg + +# Secret server salt 16 Bytes +SECRET_PROVIDER_SALT = yrL0M504mvHtOl9u + +# Private Key for EdDSA Signature Crockford32 encoded +PRIVATE_SIG_KEY = 4X0YRNW8NSXSF991XRBJ0P66XD00JQ7XJC55PRD76PW5Y32N71GG + +# Directory with our terms of service. +TERMS_DIR = ${DATADIR}tos/ + +# Etag / filename for the terms of service. +TERMS_ETAG = 0 + + +# Directory with our privacy policy. +PRIVACY_DIR = ${DATADIR}pp/ + +# Etag / filename for the privacy policy. +PRIVACY_ETAG = 0 + + +[frosix-merchant-backend] +# Base URL of our payment backend +PAYMENT_BACKEND_URL = http://localhost:9976/ + +# API Key to send to the backend for authorization +# API_KEY = + +[authorization-question] +COST = TESTKUDOS:1.0 + +[authorization-file] +COST = TESTKUDOS:1.0 + +[taler] +CURRENCY = TESTKUDOS + +[frosixdb-postgres] +#The connection string the plugin has to use for connecting to the database +CONFIG = postgres:///frosix +\ No newline at end of file diff --git a/src/cli/Makefile.am b/src/cli/Makefile.am @@ -0,0 +1,38 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/libfrosix + +bin_PROGRAMS = \ + frosix-reducer + +check_SCRIPTS = \ + test-frosix.sh + +AM_TESTS_ENVIRONMENT=export FROSIX_PREFIX=$${FROSIX_PREFIX:-@libdir@};export PATH=$${FROSIX_PREFIX:-@prefix@}/bin:$$PATH; + +TESTS = \ + $(check_SCRIPTS) + +frosix_reducer_SOURCES = \ + frosix-cli-redux.c +frosix_reducer_LDADD = \ + $(top_builddir)/src/util/libfrosixutil.la \ + $(top_builddir)/src/libfrosix/libfrosix.la \ + $(top_builddir)/src/restclient/libfrosixrest.la \ + $(top_builddir)/src/libfrostdistkeygen/libfrostdistkeygen.la \ + $(top_builddir)/src/libfrostverify/libfrostverify.la \ + -ltalerjson \ + -ltalerutil \ + -lgnunetjson \ + -lgnunetcurl \ + -lgnunetutil \ + -ljansson \ + $(XLIB) + +EXTRA_DIST = \ + test-frosix_providerlist.json \ + test-frosix_1.conf \ + test-frosix_2.conf \ + test-frosix_3.conf \ + test-frosix_4.conf \ + test-frosix_5.conf \ + $(check_SCRIPTS) +\ No newline at end of file diff --git a/src/cli/frosix-cli-redux.c b/src/cli/frosix-cli-redux.c @@ -0,0 +1,568 @@ +/* + This file is part of Frosix + Copyright (C) 2020,2021,2022 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file cli/frosix-cli-redux.c + * @brief command line tool for our reducer + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + * @author Joel Urech + */ + +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_curl_lib.h> +#include "frosix.h" +#include <taler/taler_util.h> +#include <taler/taler_error_codes.h> +#include <taler/taler_json_lib.h> +#include "frosix_util_lib.h" + +/** + * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule(). + */ +static struct GNUNET_CURL_RescheduleContext *rc; + +/** + * Curl context for communication with anastasis backend + */ +static struct GNUNET_CURL_Context *ctx; + +/** + * Input to -a option given. + */ +static char *input = NULL; + +/** + * Output filename, if given. + */ +static char *output_filename = NULL; + +/** + * Message we want to sign, -m option. +*/ +static char *message = NULL; + +/** + * JSON containing arguments for action + */ +static json_t *arguments; + +/** + * JSON containing data from stdin +*/ +static json_t *std_input; + +/** + * Handle to an ongoing action. + */ +static struct FROSIX_ReduxAction *ra; + +/** + * Return value from main. + */ +static int global_ret; + + +/** + * Persist a json state, report errors. + * + * @param state to persist + * @param filename where to write the state to, NULL for stdout + */ +static void +persist_new_state (json_t *state, + const char *filename) +{ + if (NULL != filename) + { + if (0 != + json_dump_file (state, + filename, + JSON_INDENT (1))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not dump state to `%s'\n", + filename); + return; + } + return; + } + { + char *state_str = json_dumps (state, + JSON_INDENT (1)); + if (-1 >= + fprintf (stdout, + "%s", + state_str)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not dump state to stdout\n"); + GNUNET_free (state_str); + return; + } + GNUNET_free (state_str); + } +} + + +/** + * @brief Shutdown the application. + * + * @param cls closure + */ +static void +shutdown_task (void *cls) +{ + (void) cls; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Shutdown initiated\n"); + if (NULL != ra) + { + FROSIX_redux_action_cancel (ra); + } + if (NULL != ctx) + { + GNUNET_CURL_fini (ctx); + ctx = NULL; + } + if (NULL != rc) + { + GNUNET_CURL_gnunet_rc_destroy (rc); + rc = NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Shutdown complete\n"); +} + + +/** + * Function called with the results of #FROSIX_redux_action(). + * + * @param cls closure + * @param error_code Error code + * @param result_state new state as result + */ +static void +action_cb (void *cls, + enum TALER_ErrorCode error_code, + json_t *result_state) +{ + (void) cls; + ra = NULL; + if (NULL != result_state) + + persist_new_state (result_state, + output_filename); + + if (TALER_EC_NONE != error_code) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Redux failed with error %d: %s\n", + error_code, + TALER_ErrorCode_get_hint (error_code)); + json_dumpf (result_state, + stderr, + JSON_INDENT (2)); + fprintf (stderr, "action_cb - error\n"); + } + + /* free json argument and result */ + json_decref (result_state); + + GNUNET_SCHEDULER_shutdown (); + global_ret = (TALER_EC_NONE != error_code) ? 1 : 0; +} + + +/** + * @brief Start the application + * + * @param cls closure + * @param args arguments left + * @param cfgfile config file name + * @param cfg handle for the configuration file + */ +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + (void) cls; + json_error_t error; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Starting frosix-reducer\n"); + GNUNET_SCHEDULER_add_shutdown (&shutdown_task, + NULL); + + /* action processing */ + { + const char *action = args[0]; + + if (NULL == action) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "You must specify an action as the first argument (or `-k' or `-s')\n"); + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Example: frosix-reducer --keygen -a 'json-formatted-argument'\n"); + GNUNET_SCHEDULER_shutdown (); + global_ret = 1; + return; + } + + /*** KEYGEN ***/ + if (0 == strcasecmp (action, + "keygen")) + { + /* load json file from std input */ + std_input = json_loadf (stdin, + JSON_DECODE_ANY, + &error); + if (NULL == std_input) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to parse arguments on line %u:%u: %s!\n", + error.line, + error.column, + error.text); + GNUNET_SCHEDULER_shutdown (); + global_ret = 1; + return; + } + + /* initialize HTTP client event loop */ + ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, + &rc); + rc = GNUNET_CURL_gnunet_rc_create (ctx); + + FROSIX_redux_init (ctx); + + ra = FROSIX_redux_keygen_start (std_input, + &action_cb, + cls); + } + + /*** REQUEST-CHALLENGE ***/ + if (0 == strcasecmp (action, + "request-challenge")) + { + /* check if -a and -m flag, abort if not found */ + if (NULL != input && NULL != message) + { + std_input = json_loadf (stdin, + JSON_DECODE_ANY, + &error); + if (NULL == std_input) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to parse arguments on line %u:%u: %s!\n", + error.line, + error.column, + error.text); + GNUNET_SCHEDULER_shutdown (); + global_ret = 1; + return; + } + + arguments = json_loads (input, + JSON_DECODE_ANY, + &error); + if (NULL == arguments) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to parse arguments on line %u:%u: %s!\n", + error.line, + error.column, + error.text); + GNUNET_SCHEDULER_shutdown (); + global_ret = 1; + return; + } + } + else { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to parse arguments on line %u:%u: %s!\n", + error.line, + error.column, + error.text); + GNUNET_SCHEDULER_shutdown (); + global_ret = 1; + return; + } + + /* initialize HTTP client event loop */ + ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, + &rc); + rc = GNUNET_CURL_gnunet_rc_create (ctx); + + FROSIX_redux_init (ctx); + + ra = FROSIX_redux_challenge_request_start (std_input, + arguments, + message, + &action_cb, + cls); + } + + /*** SIGN ***/ + if (0 == strcasecmp (action, + "sign")) + { + /* check if -a and -m flag, abort if not found */ + if (NULL != input && NULL != message) + { + std_input = json_loadf (stdin, + JSON_DECODE_ANY, + &error); + if (NULL == std_input) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to parse arguments on line %u:%u: %s!\n", + error.line, + error.column, + error.text); + GNUNET_SCHEDULER_shutdown (); + global_ret = 1; + return; + } + + arguments = json_loads (input, + JSON_DECODE_ANY, + &error); + if (NULL == arguments) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to parse arguments on line %u:%u: %s!\n", + error.line, + error.column, + error.text); + GNUNET_SCHEDULER_shutdown (); + global_ret = 1; + return; + } + } + else { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to parse arguments on line %u:%u: %s!\n", + error.line, + error.column, + error.text); + GNUNET_SCHEDULER_shutdown (); + global_ret = 1; + return; + } + + /* initialize HTTP client event loop */ + ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, + &rc); + rc = GNUNET_CURL_gnunet_rc_create (ctx); + + FROSIX_redux_init (ctx); + + ra = FROSIX_redux_sign_start (std_input, + arguments, + message, + &action_cb, + cls); + } + + /*** VERIFY ***/ + if (0 == strcasecmp (action, + "verify")) + { + /* check if -m flag, abort if not found */ + if (NULL != message) + { + std_input = json_loadf (stdin, + JSON_DECODE_ANY, + &error); + if (NULL == std_input) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to parse arguments on line %u:%u: %s!\n", + error.line, + error.column, + error.text); + GNUNET_SCHEDULER_shutdown (); + global_ret = 1; + return; + } + } + else { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to parse arguments on line %u:%u: %s!\n", + error.line, + error.column, + error.text); + GNUNET_SCHEDULER_shutdown (); + global_ret = 1; + return; + } + + /* verify signature and return OK */ + if (GNUNET_OK != FROSIX_verify_signature (message, + std_input)) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to verify signature!\n"); + global_ret = 1; + } + else { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Signature verified!\n"); + } + } + + /*** EXPORT-PK ***/ + if (0 == strcasecmp (action, + "export-pk")) + { + std_input = json_loadf (stdin, + JSON_DECODE_ANY, + &error); + if (NULL == std_input) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to parse arguments on line %u:%u: %s!\n", + error.line, + error.column, + error.text); + GNUNET_SCHEDULER_shutdown (); + global_ret = 1; + return; + } + + FROSIX_export_public_key (std_input, + &action_cb, + cls); + } + + /*** VERIFY-PK ***/ + if (0 == strcasecmp (action, + "verify-pk")) + { + std_input = json_loadf (stdin, + JSON_DECODE_ANY, + &error); + if (NULL == std_input) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to parse arguments on line %u:%u: %s!\n", + error.line, + error.column, + error.text); + GNUNET_SCHEDULER_shutdown (); + global_ret = 1; + return; + } + + /* verify signature and return OK */ + if (GNUNET_OK != FROSIX_verify_public_key (std_input)) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to verify public key!\n"); + global_ret = 1; + } + else { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Public key verified!\n"); + } + } + + /*** DELETE-KEY ***/ + if (0 == strcasecmp (action, + "delete-key")) + { + /* load json file from std input */ + std_input = json_loadf (stdin, + JSON_DECODE_ANY, + &error); + if (NULL == std_input) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Failed to parse arguments on line %u:%u: %s!\n", + error.line, + error.column, + error.text); + GNUNET_SCHEDULER_shutdown (); + global_ret = 1; + return; + } + + /* initialize HTTP client event loop */ + ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, + &rc); + rc = GNUNET_CURL_gnunet_rc_create (ctx); + + FROSIX_redux_init (ctx); + + ra = FROSIX_redux_key_delete_start (std_input, + &action_cb, + cls); + } + } +} + + +int +main (int argc, + char *const *argv) +{ + /* the available command line options */ + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_option_string ('a', + "arguments", + "JSON", + "pass a JSON string containing arguments to cli", + &input), + GNUNET_GETOPT_option_string ('o', + "output", + "Filename", + "define output filename", + &output_filename), + GNUNET_GETOPT_option_string ('m', + "message", + "Message to sign", + "The message to sign", + &message), + GNUNET_GETOPT_OPTION_END + }; + enum GNUNET_GenericReturnValue ret; + + /* FIRST get the libtalerutil initialization out + of the way. Then throw that one away, and force + the SYNC defaults to be used! */ + (void) TALER_project_data_default (); + GNUNET_OS_init (FROSIX_project_data_default ()); + ret = GNUNET_PROGRAM_run (argc, + argv, + "frosix-reducer", + "This is an application for using Frosix.\n", + options, + &run, + NULL); + if (GNUNET_SYSERR == ret) + return 3; + if (GNUNET_NO == ret) + return 0; + return global_ret; +} + + +/* end of frosix-cli-redux.c */ diff --git a/src/cli/test-frosix.sh b/src/cli/test-frosix.sh @@ -0,0 +1,163 @@ +#!/bin/bash +# This file is in the public domain. + +set -eu + +# Exit, with status code "skip" (no 'real' failure) +function exit_skip() { + echo " SKIP: $1" + exit 77 +} + +# Exit, with error message (hard failure) +function exit_fail() { + echo " FAIL: $@" + exit 1 +} + +# Cleanup to run whenever we exit +function cleanup() +{ + for n in $(jobs -p) + do + kill $n 2> /dev/null || true + done + rm -f "$SIGN_DOCUMENT" "$SIGNATURE" + wait +} + +# Install cleanup handler (except for kill -9) +trap cleanup EXIT + +#echo -n "Testing for jq" +#jq -h > /dev/null || exit_skip "jq required" +#echo " FOUND" +echo -n "Testing for wget" +wget -h > /dev/null || exit_skip "wget required" +echo " FOUND" +echo -n "Testing for frosix-httpd ..." +frosix-httpd -h > /dev/null || exit_skip "frosix-httpd required" +echo " FOUND" +echo -n "Testing for frosix-reducer ..." +frosix-reducer -h > /dev/null || exit_skip "frosix-reducer required" +echo " FOUND" + +# Files and config +SIGN_DOCUMENT=$(mktemp sign_documentXXXXXX.json) +SIGNATURE=$(mktemp signatureXXXXXX.json) + +PLIST="test-frosix_providerlist.json" + +CONF_1="test-frosix_1.conf" +CONF_2="test-frosix_2.conf" +CONF_3="test-frosix_3.conf" +CONF_4="test-frosix_4.conf" +CONF_5="test-frosix_5.conf" + +BURL_1="http://localhost:9967" +BURL_2="http://localhost:9968" +BURL_3="http://localhost:9969" +BURL_4="http://localhost:9970" +BURL_5="http://localhost:9971" + +AUTH='{"1":"Tobias","3":"Tobias","5":"Tobias"}' +MSG="My very important message!" + +# Init db +echo -n "Initialize frosix database ..." +TARGET_DB_1=`frosix-config -c "${CONF_1}" -s frosixdb-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///"` +TARGET_DB_2=`frosix-config -c "${CONF_2}" -s frosixdb-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///"` +TARGET_DB_3=`frosix-config -c "${CONF_3}" -s frosixdb-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///"` +TARGET_DB_4=`frosix-config -c "${CONF_4}" -s frosixdb-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///"` +TARGET_DB_5=`frosix-config -c "${CONF_5}" -s frosixdb-postgres -o CONFIG | sed -e "s/^postgres:\/\/\///"` + +dropdb "${TARGET_DB_1}" >/dev/null 2>/dev/null || true +createdb "${TARGET_DB_1}" || exit_skip "Could not create database ${TARGET_DB_1}" +frosix-dbinit -c "${CONF_1}" &> dbinit_1.log +dropdb "${TARGET_DB_2}" >/dev/null 2>/dev/null || true +createdb "${TARGET_DB_2}"|| exit_skip "Could not create database ${TARGET_DB_2}" +frosix-dbinit -c "${CONF_2}" &> dbinit_2.log +dropdb "${TARGET_DB_3}" >/dev/null 2>/dev/null || true +createdb "${TARGET_DB_3}" || exit_skip "Could not create database ${TARGET_DB_3}" +frosix-dbinit -c "${CONF_3}" &> dbinit_3.log +dropdb "${TARGET_DB_4}" >/dev/null 2>/dev/null || true +createdb "${TARGET_DB_4}" || exit_skip "Could not create database ${TARGET_DB_4}" +frosix-dbinit -c "${CONF_4}" &> dbinit_4.log +dropdb "${TARGET_DB_5}" >/dev/null 2>/dev/null || true +createdb "${TARGET_DB_5}" || exit_skip "Could not create database ${TARGET_DB_5}" +frosix-dbinit -c "${CONF_5}" &> dbinit_5.log + +echo " OK" + +echo -n "Start frosix-httpd ..." +frosix-httpd -L DEBUG -c "${CONF_1}" &> httpd_1.log & +frosix-httpd -L DEBUG -c "${CONF_2}" &> httpd_2.log & +frosix-httpd -L DEBUG -c "${CONF_3}" &> httpd_3.log & +frosix-httpd -L DEBUG -c "${CONF_4}" &> httpd_4.log & +frosix-httpd -L DEBUG -c "${CONF_5}" &> httpd_5.log & + +echo " OK" + +echo -n "Waiting for frosix services ..." + +# Wait for frosix to be available +for n in $(seq 1 50) +do + echo -n "." + sleep 0.1 + OK=0 + # bankfrosix_01 + wget --tries=1 --timeout=1 "${BURL_1}/config" -o /dev/null -O /dev/null >/dev/null || continue + # bankfrosix_02 + wget --tries=1 --timeout=1 "${BURL_2}/config" -o /dev/null -O /dev/null >/dev/null || continue + # bankfrosix_03 + wget --tries=1 --timeout=1 "${BURL_3}/config" -o /dev/null -O /dev/null >/dev/null || continue + # bankfrosix_04 + wget --tries=1 --timeout=1 "${BURL_4}/config" -o /dev/null -O /dev/null >/dev/null || continue + # bankfrosix_05 + wget --tries=1 --timeout=1 "${BURL_5}/config" -o /dev/null -O /dev/null >/dev/null || continue + OK=1 + break +done +if [ 1 != $OK ] +then + exit_skip "Failed to launch frosix service" +fi + +echo " OK" + +# Start with key generation +echo -n "Start distributed key generation ..." +frosix-reducer keygen -o "${SIGN_DOCUMENT}" < "${PLIST}" +RET_KG=$? + +if [ "$RET_KG" != "0" ] +then + exit_fail "Key generation failed! Expected return code 0, got $RET_KG" +fi + +echo " OK" + +# Sign a message +echo -n "Sign a message ..." +frosix-reducer sign -a "${AUTH}" -m "${MSG}" -o "${SIGNATURE}" < "${SIGN_DOCUMENT}" +RET_S=$? + +if [ "$RET_S" != "0" ] +then + exit_fail "Signing failed! Expected return code 0, got $RET_S" +fi + +echo " OK" + +# Verify the signature +echo -n "Verify the signature ..." +frosix-reducer verify -m "${MSG}" < "${SIGNATURE}" +RET_V=$? + +if [ "$RET_V" != "0" ] +then + exit_fail "Verification of signature failed!" +fi + +exit 0 diff --git a/src/cli/test-frosix_1.conf b/src/cli/test-frosix_1.conf @@ -0,0 +1,20 @@ +# This file is in the public domain. +[frosix] +# Which HTTP port does the backend listen on? Only used if "SERVE" is 'tcp'. +PORT = 9967 + +# Display name of the business running this anastasis provider. +BUSINESS_NAME = "Frosix Signing Service #1 Inc" + +# Server salt 16 Byte +PROVIDER_SALT = gUfO1KGOKYIFlFQg + +# Secret server salt 16 Bytes +SECRET_PROVIDER_SALT = yrL0M504mvHtOl9u + +# Private Key for EdDSA Signature Crockford32 encoded +PRIVATE_SIG_KEY = 4X0YRNW8NSXSF991XRBJ0P66XD00JQ7XJC55PRD76PW5Y32N71GG + +[frosixdb-postgres] +#The connection string the plugin has to use for connecting to the database +CONFIG = postgres:///frosixcheck1 diff --git a/src/cli/test-frosix_2.conf b/src/cli/test-frosix_2.conf @@ -0,0 +1,20 @@ +# This file is in the public domain. +[frosix] +# Which HTTP port does the backend listen on? Only used if "SERVE" is 'tcp'. +PORT = 9968 + +# Display name of the business running this anastasis provider. +BUSINESS_NAME = "Frosix Signing Service #2 Inc" + +# Server salt 16 Byte +PROVIDER_SALT = gUfO1KGOKYIFlFQg + +# Secret server salt 16 Bytes +SECRET_PROVIDER_SALT = yrL0M504mvHtOl9u + +# Private Key for EdDSA Signature Crockford32 encoded +PRIVATE_SIG_KEY = 5VQWCG9AMVENF7D3SBYTRGZ7Z0NDWMXKM6QJG4E0E9SAANABG5SG + +[frosixdb-postgres] +#The connection string the plugin has to use for connecting to the database +CONFIG = postgres:///frosixcheck2 diff --git a/src/cli/test-frosix_3.conf b/src/cli/test-frosix_3.conf @@ -0,0 +1,20 @@ +# This file is in the public domain. +[frosix] +# Which HTTP port does the backend listen on? Only used if "SERVE" is 'tcp'. +PORT = 9969 + +# Display name of the business running this anastasis provider. +BUSINESS_NAME = "Frosix Signing Service #3 Inc" + +# Server salt 16 Byte +PROVIDER_SALT = gUfO1KGOKYIFlFQg + +# Secret server salt 16 Bytes +SECRET_PROVIDER_SALT = yrL0M504mvHtOl9u + +# Private Key for EdDSA Signature Crockford32 encoded +PRIVATE_SIG_KEY = AT9WWYX28FX2M7NQPZQWGJ29KK1KRH267ZADER3JBTT5WC5B9290 + +[frosixdb-postgres] +#The connection string the plugin has to use for connecting to the database +CONFIG = postgres:///frosixcheck3 diff --git a/src/cli/test-frosix_4.conf b/src/cli/test-frosix_4.conf @@ -0,0 +1,20 @@ +# This file is in the public domain. +[frosix] +# Which HTTP port does the backend listen on? Only used if "SERVE" is 'tcp'. +PORT = 9970 + +# Display name of the business running this anastasis provider. +BUSINESS_NAME = "Frosix Signing Service #4 Inc" + +# Server salt 16 Byte +PROVIDER_SALT = gUfO1KGOKYIFlFQg + +# Secret server salt 16 Bytes +SECRET_PROVIDER_SALT = yrL0M504mvHtOl9u + +# Private Key for EdDSA Signature Crockford32 encoded +PRIVATE_SIG_KEY = M3VQ2HE37NGB6TNSJY3H59R2KWQ5V56A9ZFJCS5E24CRSCJ6N8C0 + +[frosixdb-postgres] +#The connection string the plugin has to use for connecting to the database +CONFIG = postgres:///frosixcheck4 diff --git a/src/cli/test-frosix_5.conf b/src/cli/test-frosix_5.conf @@ -0,0 +1,20 @@ +# This file is in the public domain. +[frosix] +# Which HTTP port does the backend listen on? Only used if "SERVE" is 'tcp'. +PORT = 9971 + +# Display name of the business running this anastasis provider. +BUSINESS_NAME = "Frosix Signing Service #5 Inc" + +# Server salt 16 Byte +PROVIDER_SALT = gUfO1KGOKYIFlFQg + +# Secret server salt 16 Bytes +SECRET_PROVIDER_SALT = yrL0M504mvHtOl9u + +# Private Key for EdDSA Signature Crockford32 encoded +PRIVATE_SIG_KEY = MYA6TVYRXXK6MQSFG0K8B50BBKR2XMX6S7P8WT974DRGZJ3TKZQG + +[frosixdb-postgres] +#The connection string the plugin has to use for connecting to the database +CONFIG = postgres:///frosixcheck5 diff --git a/src/cli/test-frosix_providerlist.json b/src/cli/test-frosix_providerlist.json @@ -0,0 +1,43 @@ +{ + "threshold": 3, + "expiration": 5, + "providers": [ + { + "url": "localhost:9967/", + "public_key": "VP194475JRR8PC32FHCGBWA0J5R0SMR9XHN8FZAVYKBR4MQ0RG2G", + "auth_method": "question", + "auth_data": "My second name", + "auth_answer": "Tobias" + }, + { + "url": "localhost:9968/", + "public_key": "9C686GSP4AN2CN20CG7ZW0PEHFQHKXA3MRKJA1FG8WGJ2MH465M0", + "auth_method": "question", + "auth_data": "My second name", + "auth_answer": "Tobias" + }, + { + "url": "localhost:9969/", + "public_key": "2CMV7SAK8KNS60D3Y7ECN2BBBGD9RKY724ZEV27FW2WPQ3H19HBG", + "auth_method": "question", + "auth_data": "My second name", + "auth_answer": "Tobias" + }, + { + "url": "localhost:9970/", + "public_key": "ZC8C7D41CW0ET546P0XM8F68EGYXRPN0GVRGSV41QP1ZFXQT2B40", + "auth_method": "question", + "auth_data": "My second name", + "auth_answer": "Tobias" + + }, + { + "url": "localhost:9971/", + "public_key": "DPWM42WB4KSK83MDW20MMVASDCM995HNNPFCXZ06M26G0KEQ698G", + "auth_method": "question", + "auth_data": "My second name", + "auth_answer": "Tobias" + } + + ] +} diff --git a/src/frosixdb/Makefile.am b/src/frosixdb/Makefile.am @@ -0,0 +1,68 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/backend + +plugindir = $(libdir)/frosix + +plugin_LTLIBRARIES = \ + libfrosix_plugin_db_postgres.la + +sqldir = $(prefix)/share/frosix/sql/ + +sql_DATA = \ + versioning.sql \ + frosix-0001.sql \ + drop.sql + +pkgcfgdir = $(prefix)/share/frosix/config.d/ + +pkgcfg_DATA = \ + frosix_db_postgres.conf + +bin_PROGRAMS = \ + frosix-dbinit + +frosix_dbinit_SOURCES = \ + frosix-dbinit.c + +frosix_dbinit_LDADD = \ + $(top_builddir)/src/util/libfrosixutil.la \ + $(LIBGCRYPT_LIBS) \ + libfrosixdb.la \ + -lgnunetutil \ + -ltalerutil \ + -ltalerpq \ + $(XLIB) + + +lib_LTLIBRARIES = \ + libfrosixdb.la + +libfrosixdb_la_SOURCES = \ + frosix_db_plugin.c +libfrosixdb_la_LIBADD = \ + -lgnunetpq \ + -lpq \ + -lgnunetutil \ + -lltdl \ + $(XLIB) +libfrosixdb_la_LDFLAGS = \ + $(POSTGRESQL_LDFLAGS) \ + -version-info 2:0:0 \ + -no-undefined + +libfrosix_plugin_db_postgres_la_SOURCES = \ + plugin_frosix_postgres.c +libfrosix_plugin_db_postgres_la_LIBADD = \ + $(LTLIBINTL) +libfrosix_plugin_db_postgres_la_LDFLAGS = \ + $(FROSIX_PLUGIN_LDFLAGS) \ + -lgnunetpq \ + -lpq \ + -ltalerpq \ + -ltalerutil \ + -lgnunetutil \ + $(XLIB) + +EXTRA_DIST = \ + $(pkgcfg_DATA) \ + $(sql_DATA) diff --git a/src/frosixdb/drop.sql b/src/frosixdb/drop.sql @@ -0,0 +1,25 @@ +-- +-- This file is part of Frosix +-- Copyright (C) 2014--2022 Anastasis Systems SA +-- +-- Frosix is free software; you can redistribute it and/or modify it under the +-- terms of the GNU General Public License as published by the Free Software +-- Foundation; either version 3, or (at your option) any later version. +-- +-- Frosix is distributed in the hope that it will be useful, but WITHOUT ANY +-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +-- A PARTICULAR PURPOSE. See the GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along with +-- Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +-- + +-- Everything in one big transaction +BEGIN; + +-- Unregister patch (0001.sql) +SELECT _v.unregister_patch('frosix-0001'); +DROP SCHEMA frosix CASCADE; + +-- And we're out of here... +COMMIT; diff --git a/src/frosixdb/frosix-0001.sql b/src/frosixdb/frosix-0001.sql @@ -0,0 +1,133 @@ +-- +-- This file is part of Frosix +-- Copyright (C) 2022, 2023 Joel Urech +-- +-- Frosix is free software; you can redistribute it and/or modify it under the +-- terms of the GNU Affero General Public License as published by the Free Software +-- Foundation; either version 3, or (at your option) any later version. +-- +-- Frosix is distributed in the hope that it will be useful, but WITHOUT ANY +-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +-- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +-- +-- You should have received a copy of the GNU Affero General Public License along with +-- Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +-- + +-- Everything in one big transaction +BEGIN; + +-- Check patch versioning is in place. +SELECT _v.register_patch('frosix-0001', NULL, NULL); + +CREATE SCHEMA frosix; +COMMENT ON SCHEMA frosix IS 'frosix backend data'; + +SET search_path TO frosix; + + +CREATE TABLE IF NOT EXISTS frosix_key + (key_id BYTEA PRIMARY KEY CHECK(LENGTH(key_id)=64), -- hash of encryption key + identifier INT NOT NULL, + expiration INT NOT NULL, + encryption_nonce BYTEA CHECK(LENGTH(encryption_nonce)=24), + enc_key_data BYTEA CHECK(LENGTH(enc_key_data)=80), -- (secret share, public_key + MAC) + challenge_data BYTEA CHECK(LENGTH(challenge_data)=64)); -- salted_hash H(auth_data, auth_nonce) auth_data=answer, phone number, etc. + +COMMENT ON TABLE frosix_key + IS 'Saves all needed data to participate in a signing process'; +COMMENT ON COLUMN frosix_key.key_id + IS 'The key id identifies this key record. It is the hash of the key which was used to encrypt the data in this record'; +COMMENT ON COLUMN frosix_key.identifier + IS 'Identifier in the signing group'; +COMMENT ON COLUMN frosix_key.expiration + IS 'At which date the key record expire'; +COMMENT ON COLUMN frosix_key.encryption_nonce + IS 'Nonce used in encryption and decryption of the key data'; +COMMENT ON COLUMN frosix_key.enc_key_data + IS 'Stores the encrypted secret key share and the corresponding public key which is used in the signing process'; +COMMENT ON COLUMN frosix_key.challenge_data + IS 'Stores the salted hash of the challenge data which are used to authenticate a signing request.'; + + +CREATE TABLE IF NOT EXISTS frosix_public_commitments + (dkg_id BYTEA PRIMARY KEY CHECK(LENGTH(dkg_id)=64), -- h(context_string || public provider salt) + time_stamp TIMESTAMP NOT NULL, + commitments BYTEA NOT NULL); + +COMMENT ON TABLE frosix_public_commitments + IS 'Saves commitments used in distributed key generation'; +COMMENT ON COLUMN frosix_public_commitments.dkg_id + IS 'ID of the corresponding dkg'; +COMMENT ON COLUMN frosix_public_commitments.time_stamp + IS 'Timestamp from the creation of this record. Used for garbage collection'; +COMMENT ON COLUMN frosix_public_commitments.commitments + IS 'The stored commitments from all other participants'; + + +CREATE INDEX IF NOT EXISTS frosix_public_commitments_expiration_index + ON frosix_public_commitments + (dkg_id,time_stamp); + +COMMENT ON INDEX frosix_public_commitments_expiration_index + IS 'for dkg commitments garbage collection'; + + +CREATE TABLE IF NOT EXISTS frosix_challengecode + (challenge_id BYTEA CHECK(LENGTH(challenge_id)=64) NOT NULL, + code INT8 NOT NULL, + creation_date INT8 NOT NULL, + expiration_date INT8 NOT NULL, + retransmission_date INT8 NOT NULL DEFAULT 0, + retry_counter INT4 NOT NULL, + satisfied BOOLEAN NOT NULL DEFAULT FALSE); + +COMMENT ON TABLE frosix_challengecode + IS 'Stores a code which is checked for the authentication by SMS, E-Mail..'; +COMMENT ON COLUMN frosix_challengecode.challenge_id + IS 'ID of the challenge, is unique for each message and key pair'; +COMMENT ON COLUMN frosix_challengecode.code + IS 'The pin code which is sent to the user and verified'; +COMMENT ON COLUMN frosix_challengecode.creation_date + IS 'Creation date of the code'; +COMMENT ON COLUMN frosix_challengecode.retransmission_date + IS 'When did we last transmit the challenge to the user'; +COMMENT ON COLUMN frosix_challengecode.expiration_date + IS 'When will the code expire'; +COMMENT ON COLUMN frosix_challengecode.retry_counter + IS 'How many tries are left for this code must be > 0'; +COMMENT ON COLUMN frosix_challengecode.satisfied + IS 'Has this challenge been satisfied by the user, used if it is not enough for the user to know the code (like for video identification or SEPA authentication). For SMS/E-mail/Post verification, this field being FALSE does not imply that the user did not meet the challenge.'; + + +CREATE INDEX IF NOT EXISTS frosix_challengecode_expiration_index + ON frosix_challengecode + (challenge_id,expiration_date); + +COMMENT ON INDEX frosix_challengecode_expiration_index + IS 'for challenge garbage collection'; + + +CREATE TABLE IF NOT EXISTS frosix_seed + (seed_id BYTEA PRIMARY KEY CHECK(LENGTH(seed_id)=64) NOT NULL, --H(H(enc_key), i, D, E) + seed BYTEA CHECK(LENGTH(seed)=32) NOT NULL, + time_stamp TIMESTAMP NOT NULL); + +COMMENT ON TABLE frosix_seed + IS 'Stores the random seed to generate the commitment in Frosix Sign between round 1 and 2'; +COMMENT ON COLUMN frosix_seed.seed_id + IS 'Identifier of the stored seed, instantiated as hash over the resulting commitment and the encryption key'; +COMMENT ON COLUMN frosix_seed.seed + IS 'This seed must never be used for two signatures! Delete immediately after use!'; +COMMENT ON COLUMN frosix_seed.time_stamp + IS 'Timestamp of creation, used for garbage collection'; + +CREATE INDEX IF NOT EXISTS frosix_seed_expiration_index + ON frosix_seed + (seed_id,time_stamp); + +COMMENT ON INDEX frosix_seed_expiration_index + IS 'For seed garbage collection'; + +-- Complete transaction +COMMIT; diff --git a/src/frosixdb/frosix-dbinit.c b/src/frosixdb/frosix-dbinit.c @@ -0,0 +1,162 @@ +/* + This file is part of Frosix + Copyright (C) 2019-2021 SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file frosixdb/frosix-dbinit.c + * @brief Create tables for the merchant database. + * @author Dennis Neufeld + * @author Dominik Meister + */ +#include "platform.h" +#include "frosix_database_lib.h" +#include "frosix_util_lib.h" +#include <gnunet/gnunet_time_lib.h> +#include <gnunet/gnunet_util_lib.h> +#include <taler/taler_util.h> + + +/** + * Return value from main(). + */ +static int global_ret; + +/** + * -r option: do full DB reset + */ +static int reset_db; + +/** + * -g option: do garbage collection + */ +static int gc_db; + +/** + * Main function that will be run. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct FROSIX_DatabasePlugin *plugin; + + (void) cls; + (void) args; + (void) cfgfile; + + if (NULL == + (plugin = FROSIX_DB_plugin_load (cfg))) + { + fprintf (stderr, + "Failed to initialize database plugin.\n"); + global_ret = EXIT_NOTINSTALLED; + return; + } + if (reset_db) + { + if (GNUNET_OK != plugin->drop_tables (plugin->cls)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not drop tables as requested. Either database was not yet initialized, or permission denied. Consult the logs. Will still try to create new tables.\n"); + } + } + if (GNUNET_OK != + plugin->create_tables (plugin->cls)) + { + global_ret = EXIT_FAILURE; + FROSIX_DB_plugin_unload (plugin); + return; + } + if (gc_db) + { + struct GNUNET_TIME_Absolute expire_backups; + struct GNUNET_TIME_Absolute expire_payments; + struct GNUNET_TIME_Absolute now; + + now = GNUNET_TIME_absolute_get (); + expire_backups = GNUNET_TIME_absolute_subtract ( + now, + GNUNET_TIME_relative_multiply ( + GNUNET_TIME_UNIT_MONTHS, + 6)); + expire_payments = GNUNET_TIME_absolute_subtract ( + now, + GNUNET_TIME_relative_multiply ( + GNUNET_TIME_UNIT_YEARS, + 10)); + if (0 > plugin->gc (plugin->cls, + expire_backups, + expire_payments)) + { + fprintf (stderr, + "Garbage collection failed!\n"); + } + } + FROSIX_DB_plugin_unload (plugin); +} + + +/** + * The main function of the database initialization tool. + * Used to initialize the Anastasis' database. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, + char *const *argv) +{ + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_option_flag ('g', + "garbagecollect", + "remove state data from database", + &gc_db), + GNUNET_GETOPT_option_flag ('r', + "reset", + "reset database (DANGEROUS: all existing data is lost!)", + &reset_db), + + GNUNET_GETOPT_OPTION_END + }; + + /* force linker to link against libtalerutil; if we do + not do this, the linker may "optimize" libtalerutil + away and skip #TALER_OS_init(), which we do need */ + (void) TALER_project_data_default (); + GNUNET_OS_init (FROSIX_project_data_default ()); + GNUNET_assert (GNUNET_OK == + GNUNET_log_setup ("frosix-dbinit", + "INFO", + NULL)); + if (GNUNET_OK != + GNUNET_PROGRAM_run (argc, argv, + "frosix-dbinit", + "Initialize frosix database", + options, + &run, NULL)) + return 1; + return global_ret; +} + + +/* end of frosix-dbinit.c */ diff --git a/src/frosixdb/frosix_db_plugin.c b/src/frosixdb/frosix_db_plugin.c @@ -0,0 +1,147 @@ +/* + This file is part of Frosix + Copyright (C) 2015, 2016 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file frosix_db_plugin.c + * @brief Logic to load database plugin + * @author Christian Grothoff + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ +#include "platform.h" +#include "frosix_database_plugin.h" +#include <ltdl.h> +#include <gnunet/gnunet_util_lib.h> + + +/** + * Initialize the plugin. + * + * @param cfg configuration to use + * @return #GNUNET_OK on success + */ +struct FROSIX_DatabasePlugin * +FROSIX_DB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *plugin_name; + char *lib_name; + struct FROSIX_DatabasePlugin *plugin; + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, + "frosix", + "db", + &plugin_name)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "frosix", + "db"); + return NULL; + } + (void) GNUNET_asprintf (&lib_name, + "libfrosix_plugin_db_%s", + plugin_name); + GNUNET_free (plugin_name); + plugin = GNUNET_PLUGIN_load (lib_name, + (void *) cfg); + if (NULL != plugin) + plugin->library_name = lib_name; + else + lib_name = NULL; + return plugin; +} + + +/** + * Shutdown the plugin. + * + * @param plugin the plugin to unload + */ +void +FROSIX_DB_plugin_unload (struct FROSIX_DatabasePlugin *plugin) +{ + char *lib_name; + + if (NULL == plugin) + return; + lib_name = plugin->library_name; + GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name, + plugin)); + GNUNET_free (lib_name); +} + + +/** + * Libtool search path before we started. + */ +static char *old_dlsearchpath; + + +/** + * Setup libtool paths. + */ +void __attribute__ ((constructor)) +plugin_init () +{ + int err; + const char *opath; + char *path; + char *cpath; + + err = lt_dlinit (); + if (err > 0) + { + fprintf (stderr, + ("Initialization of plugin mechanism failed: %s!\n"), + lt_dlerror ()); + return; + } + opath = lt_dlgetsearchpath (); + if (NULL != opath) + old_dlsearchpath = GNUNET_strdup (opath); + path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR); + if (NULL != path) + { + if (NULL != opath) + { + GNUNET_asprintf (&cpath, "%s:%s", opath, path); + lt_dlsetsearchpath (cpath); + GNUNET_free (path); + GNUNET_free (cpath); + } + else + { + lt_dlsetsearchpath (path); + GNUNET_free (path); + } + } +} + + +/** + * Shutdown libtool. + */ +void __attribute__ ((destructor)) +plugin_fini () +{ + lt_dlsetsearchpath (old_dlsearchpath); + if (NULL != old_dlsearchpath) + { + GNUNET_free (old_dlsearchpath); + } + lt_dlexit (); +} + + +/* end of frosix_db_plugin.c */ diff --git a/src/frosixdb/frosix_db_postgres.conf b/src/frosixdb/frosix_db_postgres.conf @@ -0,0 +1,7 @@ +[frosixdb-postgres] +#The connection string the plugin has to use for connecting to the database +CONFIG = postgres:///frosix + +# Where are the SQL files to setup our tables? +# Important: this MUST end with a "/"! +SQL_DIR = $DATADIR/sql/ diff --git a/src/frosixdb/plugin_frosix_postgres.c b/src/frosixdb/plugin_frosix_postgres.c @@ -0,0 +1,1489 @@ +/* + This file is part of Frosix + Copyright (C) 2020, 2021, 2022 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file frosixdb/plugin_frosix_postgres.c + * @brief database helper functions for postgres used by Frosix + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "frosix_database_plugin.h" +#include "frosix_database_lib.h" +#include "keygen.h" +#include "frosix-httpd_dkg.h" +#include <taler/taler_pq_lib.h> +#include <gnunet/gnunet_pq_lib.h> + +/** + * How long do we keep transient accounts open (those that have + * not been paid at all, but are awaiting payment). This puts + * a cap on how long users have to make a payment after a payment + * request was generated. + */ +#define TRANSIENT_LIFETIME GNUNET_TIME_UNIT_WEEKS + +/** + * How often do we re-try if we run into a DB serialization error? + */ +#define MAX_RETRIES 3 + + +/** + * Type of the "cls" argument given to each of the functions in + * our API. + */ +struct PostgresClosure +{ + + /** + * Postgres connection handle. + */ + struct GNUNET_PQ_Context *conn; + + /** + * Underlying configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Name of the currently active transaction, NULL if none is active. + */ + const char *transaction_name; + + /** + * Currency we accept payments in. + */ + char *currency; + + /** + * Prepared statements have been initialized. + */ + bool init; +}; + + +/** + * Drop anastasis tables + * + * @param cls closure our `struct Plugin` + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +static enum GNUNET_GenericReturnValue +postgres_drop_tables (void *cls) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_Context *conn; + enum GNUNET_GenericReturnValue ret; + + conn = GNUNET_PQ_connect_with_cfg (pg->cfg, + "frosixdb-postgres", + NULL, + NULL, + NULL); + if (NULL == conn) + return GNUNET_SYSERR; + ret = GNUNET_PQ_exec_sql (conn, + "drop"); + GNUNET_PQ_disconnect (conn); + return ret; +} + + +/** + * Initialize tables. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +static enum GNUNET_GenericReturnValue +postgres_create_tables (void *cls) +{ + struct PostgresClosure *pc = cls; + struct GNUNET_PQ_Context *conn; + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("SET search_path TO frosix;"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; + + conn = GNUNET_PQ_connect_with_cfg (pc->cfg, + "frosixdb-postgres", + "frosix-", + es, + NULL); + if (NULL == conn) + return GNUNET_SYSERR; + GNUNET_PQ_disconnect (conn); + return GNUNET_OK; +} + + +/** + * Establish connection to the database. + * + * @param cls plugin context + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +static enum GNUNET_GenericReturnValue +prepare_statements (void *cls) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_PreparedStatement ps[] = { + GNUNET_PQ_make_prepare ("do_commit", + "COMMIT"), + GNUNET_PQ_make_prepare ("dkg_commitment_insert", + "INSERT INTO frosix_public_commitments " + "(dkg_id" + ",time_stamp" + ",commitments" + ") VALUES " + "($1, $2, $3);"), + GNUNET_PQ_make_prepare ("dkg_commitments_select", + "SELECT" + " commitments" + " FROM frosix_public_commitments" + " WHERE dkg_id=$1;"), + GNUNET_PQ_make_prepare ("dkg_commitments_lookup", + "SELECT" + " dkg_id" + " FROM frosix_public_commitments" + " WHERE dkg_id=$1;"), + GNUNET_PQ_make_prepare ("dkg_key_insert", + "INSERT INTO frosix_key " + "(key_id" + ",identifier" + ",expiration" + ",encryption_nonce" + ",enc_key_data" + ",challenge_data" + ") VALUES " + "($1, $2, $3, $4, $5, $6);"), + GNUNET_PQ_make_prepare ("key_lookup", + "SELECT" + " key_id" + " FROM frosix_key" + " WHERE key_id=$1;"), + GNUNET_PQ_make_prepare ("key_data_select", + "SELECT" + " identifier" + ",encryption_nonce" + ",enc_key_data" + " FROM frosix_key" + " WHERE key_id=$1;"), + GNUNET_PQ_make_prepare ("key_delete", + "DELETE" + " FROM frosix_key" + " WHERE key_id=$1;"), + GNUNET_PQ_make_prepare ("auth_hash_select", + "SELECT" + " challenge_data" + " FROM frosix_key" + " WHERE key_id=$1;"), + GNUNET_PQ_make_prepare ("seed_insert", + "INSERT INTO frosix_seed " + "(seed_id" + ",seed" + ",time_stamp" + ") VALUES " + "($1, $2, $3);"), + GNUNET_PQ_make_prepare ("seed_select", + "SELECT" + " seed" + " FROM frosix_seed" + " WHERE seed_id=$1;"), + GNUNET_PQ_make_prepare ("seed_delete", + "DELETE" + " FROM frosix_seed " + " WHERE seed_id=$1;"), + GNUNET_PQ_make_prepare ("challengecode_insert", + "INSERT INTO frosix_challengecode " + "(challenge_id" + ",code" + ",creation_date" + ",expiration_date" + ",retry_counter" + ") VALUES " + "($1, $2, $3, $4, $5);"), + GNUNET_PQ_make_prepare ("challengecode_select", + "SELECT " + " code" + ",satisfied" + " FROM frosix_challengecode" + " WHERE challenge_id=$1" + " AND retry_counter != 0;"), + GNUNET_PQ_make_prepare ("challengecode_select_meta", + "SELECT " + " code" + ",retry_counter" + ",retransmission_date" + " FROM frosix_challengecode" + " WHERE challenge_id=$1" + " AND expiration_date > $2" + " AND creation_date > $3" + " ORDER BY creation_date DESC" + " LIMIT 1;"), + GNUNET_PQ_make_prepare ("challengecode_update_retry", + "UPDATE frosix_challengecode" + " SET retry_counter=retry_counter - 1" + " WHERE challenge_id=$1" + " AND code=$2" + " AND retry_counter != 0;"), + GNUNET_PQ_make_prepare ("challengecode_mark_sent", + "UPDATE frosix_challengecode" + " SET retransmission_date=$3" + " WHERE challenge_id=$1" + " AND code=$2" + " AND creation_date IN" + " (SELECT creation_date" + " FROM frosix_challengecode" + " WHERE challenge_id=$1" + " AND code=$2" + " ORDER BY creation_date DESC" + " LIMIT 1);"), + GNUNET_PQ_make_prepare ("gc_challengecodes", + "DELETE FROM frosix_challengecode " + "WHERE " + "expiration_date < $1;"), + GNUNET_PQ_PREPARED_STATEMENT_END + }; + + { + enum GNUNET_GenericReturnValue ret; + + ret = GNUNET_PQ_prepare_statements (pg->conn, + ps); + if (GNUNET_OK != ret) + return ret; + pg->init = true; + return GNUNET_OK; + } +} + + +/** + * Check that the database connection is still up. + * + * @param cls a `struct PostgresClosure` with connection to check + */ +static void +check_connection (void *cls) +{ + struct PostgresClosure *pg = cls; + + GNUNET_PQ_reconnect_if_down (pg->conn); +} + + +/** + * Connect to the database if the connection does not exist yet. + * + * @param pg the plugin-specific state + * @param skip_prepare true if we should skip prepared statement setup + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +internal_setup (struct PostgresClosure *pg, + bool skip_prepare) +{ + if (NULL == pg->conn) + { +#if AUTO_EXPLAIN + /* Enable verbose logging to see where queries do not + properly use indices */ + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"), + GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"), + GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"), + GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"), + /* https://wiki.postgresql.org/wiki/Serializable suggests to really + force the default to 'serializable' if SSI is to be used. */ + GNUNET_PQ_make_try_execute ( + "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"), + GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"), + GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"), + GNUNET_PQ_make_execute ("SET search_path TO anastasis;"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; +#else + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("SET search_path TO frosix;"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; +#endif + struct GNUNET_PQ_Context *db_conn; + + db_conn = GNUNET_PQ_connect_with_cfg (pg->cfg, + "frosixdb-postgres", + NULL, + es, + NULL); + if (NULL == db_conn) + return GNUNET_SYSERR; + pg->conn = db_conn; + } + if (NULL == pg->transaction_name) + GNUNET_PQ_reconnect_if_down (pg->conn); + if (pg->init) + return GNUNET_OK; + if (skip_prepare) + return GNUNET_OK; + return prepare_statements (pg); +} + + +/** + * Do a pre-flight check that we are not in an uncommitted transaction. + * If we are, try to commit the previous transaction and output a warning. + * Does not return anything, as we will continue regardless of the outcome. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @return #GNUNET_OK if everything is fine + * #GNUNET_NO if a transaction was rolled back + * #GNUNET_SYSERR on hard errors + */ +static enum GNUNET_GenericReturnValue +postgres_preflight (void *cls) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("ROLLBACK"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; + + if (! pg->init) + { + if (GNUNET_OK != + internal_setup (pg, + false)) + return GNUNET_SYSERR; + } + if (NULL == pg->transaction_name) + return GNUNET_OK; /* all good */ + if (GNUNET_OK == + GNUNET_PQ_exec_statements (pg->conn, + es)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "BUG: Preflight check rolled back transaction `%s'!\n", + pg->transaction_name); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "BUG: Preflight check failed to rollback transaction `%s'!\n", + pg->transaction_name); + } + pg->transaction_name = NULL; + return GNUNET_NO; +} + + +/** + * Start a transaction. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param name unique name identifying the transaction (for debugging), + * must point to a constant + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +begin_transaction (void *cls, + const char *name) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; + + check_connection (pg); + GNUNET_break (GNUNET_OK == + postgres_preflight (pg)); + pg->transaction_name = name; + if (GNUNET_OK != + GNUNET_PQ_exec_statements (pg->conn, + es)) + { + TALER_LOG_ERROR ("Failed to start transaction\n"); + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** +* Roll back the current transaction of a database connection. +* +* @param cls the `struct PostgresClosure` with the plugin-specific state +* @return #GNUNET_OK on success +*/ +static void +rollback (void *cls) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("ROLLBACK"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; + + if (GNUNET_OK != + GNUNET_PQ_exec_statements (pg->conn, + es)) + { + TALER_LOG_ERROR ("Failed to rollback transaction\n"); + GNUNET_break (0); + } + pg->transaction_name = NULL; +} + + +/** + * Commit the current transaction of a database connection. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @return transaction status code + */ +static enum GNUNET_DB_QueryStatus +commit_transaction (void *cls) +{ + struct PostgresClosure *pg = cls; + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_PQ_QueryParam no_params[] = { + GNUNET_PQ_query_param_end + }; + + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "do_commit", + no_params); + pg->transaction_name = NULL; + return qs; +} + + +/** + * Register callback to be invoked on events of type @a es. + * + * @param cls database context to use + * @param es specification of the event to listen for + * @param timeout how long to wait for the event + * @param cb function to call when the event happens, possibly + * multiple times (until cancel is invoked) + * @param cb_cls closure for @a cb + * @return handle useful to cancel the listener + */ +static struct GNUNET_DB_EventHandler * +postgres_event_listen (void *cls, + const struct GNUNET_DB_EventHeaderP *es, + struct GNUNET_TIME_Relative timeout, + GNUNET_DB_EventCallback cb, + void *cb_cls) +{ + struct PostgresClosure *pg = cls; + + return GNUNET_PQ_event_listen (pg->conn, + es, + timeout, + cb, + cb_cls); +} + + +/** + * Stop notifications. + * + * @param eh handle to unregister. + */ +static void +postgres_event_listen_cancel (struct GNUNET_DB_EventHandler *eh) +{ + GNUNET_PQ_event_listen_cancel (eh); +} + + +/** + * Notify all that listen on @a es of an event. + * + * @param cls database context to use + * @param es specification of the event to generate + * @param extra additional event data provided + * @param extra_size number of bytes in @a extra + */ +static void +postgres_event_notify (void *cls, + const struct GNUNET_DB_EventHeaderP *es, + const void *extra, + size_t extra_size) +{ + struct PostgresClosure *pg = cls; + + return GNUNET_PQ_event_notify (pg->conn, + es, + extra, + extra_size); +} + +/** + * FIXME +*/ +static enum FROSIX_DB_StoreStatus +postgres_store_dkg_commitment ( + void *cls, + const struct FROSIX_DkgRequestIdP *dkg_id, + const struct FROSIX_DkgCommitmentsRaw *dkg_commits) +{ + struct PostgresClosure *pg = cls; + enum GNUNET_DB_QueryStatus qs; + + check_connection (pg); + GNUNET_break (GNUNET_OK == + postgres_preflight (pg)); + for (unsigned int retry = 0; retry < MAX_RETRIES; retry++) + { + if (GNUNET_OK != + begin_transaction (pg, + "dkg_commitment_insert")) + { + GNUNET_break (0); + return FROSIX_DB_STORE_STATUS_HARD_ERROR; + } + + { + + // FIXME: do some checks + struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (dkg_id), + GNUNET_PQ_query_param_timestamp (&now), + GNUNET_PQ_query_param_fixed_size (dkg_commits->ptr_commits, + dkg_commits->length), + GNUNET_PQ_query_param_end + }; + + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "dkg_commitment_insert", + params); + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + rollback (pg); + return FROSIX_DB_STORE_STATUS_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + goto retry; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_break (0); + rollback (pg); + return FROSIX_DB_STORE_STATUS_HARD_ERROR; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + qs = commit_transaction (pg); + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + goto retry; + if (qs < 0) + return FROSIX_DB_STORE_STATUS_HARD_ERROR; + return FROSIX_DB_STORE_STATUS_SUCCESS; + } + } + retry: + rollback (pg); + } + return FROSIX_DB_STORE_STATUS_SOFT_ERROR; +} + + + +/** + * FIXME +*/ +static enum GNUNET_DB_QueryStatus +postgres_get_dkg_commitment ( + void *cls, + const struct FROSIX_DkgRequestIdP *dkg_id, + struct FROSIX_DkgCommitmentsRaw *dkg_commits) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (dkg_id), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_variable_size ("commitments", + &dkg_commits->ptr_commits, + &dkg_commits->length), + GNUNET_PQ_result_spec_end + }; + + check_connection (pg); + GNUNET_break (GNUNET_OK == postgres_preflight (pg)); + + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "dkg_commitments_select", + params, + rs); +} + + +/** + * FIXME +*/ +static enum FROSIX_DB_CommitmentStatus +postgres_lookup_dkg_commitment ( + void *cls, + const struct FROSIX_DkgRequestIdP *dkg_id) +{ + enum GNUNET_DB_QueryStatus qs; + + struct PostgresClosure *pg = cls; + check_connection (pg); + GNUNET_break (GNUNET_OK == postgres_preflight (pg)); + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (dkg_id), + GNUNET_PQ_query_param_end + }; + + struct FROSIX_DkgRequestIdP id; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("dkg_id", + &id), + GNUNET_PQ_result_spec_end + }; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "dkg_commitments_lookup", + params, + rs); + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + return FROSIX_DB_COMMITMENT_STATUS_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return FROSIX_DB_COMMITMENT_STATUS_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + return FROSIX_DB_COMMITMENT_STATUS_NO_RESULTS; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + return FROSIX_DB_COMMITMENT_STATUS_ONE_RESULT; + default: + GNUNET_break (0); + return FROSIX_DB_COMMITMENT_STATUS_HARD_ERROR; + } +} + + +/** + * FIXME +*/ +static enum FROSIX_DB_StoreStatus +postgres_store_key ( + void *cls, + const struct FROST_HashCode *id, + const struct FROSIX_EncryptionNonceP *nonce, + const struct FROSIX_KeyDataEncrypted *key_data, + const struct FROSIX_ChallengeHashP *challenge_hash, + uint32_t expiration, + uint8_t identifier) +{ + struct PostgresClosure *pg = cls; + enum GNUNET_DB_QueryStatus qs; + + check_connection (pg); + GNUNET_break (GNUNET_OK == + postgres_preflight (pg)); + for (unsigned int retry = 0; retry < MAX_RETRIES; retry++) + { + if (GNUNET_OK != + begin_transaction (pg, + "dkg_key_insert")) + { + GNUNET_break (0); + return FROSIX_DB_STORE_STATUS_HARD_ERROR; + } + + { + const uint32_t id_32 = identifier; + const uint32_t expiration_32 = expiration; + // FIXME: do some checks? + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (id), + GNUNET_PQ_query_param_uint32 (&id_32), + GNUNET_PQ_query_param_uint32 (&expiration_32), + GNUNET_PQ_query_param_auto_from_type (nonce), + GNUNET_PQ_query_param_auto_from_type (key_data), + GNUNET_PQ_query_param_auto_from_type (challenge_hash), + GNUNET_PQ_query_param_end + }; + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "dkg_key_insert", + params); + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + rollback (pg); + return FROSIX_DB_STORE_STATUS_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + goto retry; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_break (0); + rollback (pg); + return FROSIX_DB_STORE_STATUS_HARD_ERROR; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + qs = commit_transaction (pg); + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + goto retry; + if (qs < 0) + return FROSIX_DB_STORE_STATUS_HARD_ERROR; + return FROSIX_DB_STORE_STATUS_SUCCESS; + } + } + retry: + rollback (pg); + } + return FROSIX_DB_STORE_STATUS_SOFT_ERROR; +} + + +/** + * FIXME +*/ +static enum FROSIX_DB_KeyStatus +postgres_lookup_key ( + void *cls, + const struct FROST_HashCode *id) +{ + enum GNUNET_DB_QueryStatus qs; + + struct PostgresClosure *pg = cls; + check_connection (pg); + GNUNET_break (GNUNET_OK == postgres_preflight (pg)); + + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (id), + GNUNET_PQ_query_param_end + }; + + struct FROST_HashCode id_db; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("key_id", + &id_db), + GNUNET_PQ_result_spec_end + }; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "key_lookup", + params, + rs); + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + return FROSIX_DB_KEY_STATUS_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return FROSIX_DB_KEY_STATUS_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + return FROSIX_DB_KEY_STATUS_NO_RESULTS; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + return FROSIX_DB_KEY_STATUS_ONE_RESULT; + default: + GNUNET_break (0); + return FROSIX_DB_KEY_STATUS_HARD_ERROR; + } +} + + +/** + * FIXME +*/ +static enum GNUNET_DB_QueryStatus +postgres_get_auth_hash ( + void *cls, + const struct FROST_HashCode *db_id, + struct FROSIX_ChallengeHashP *challenge_hash) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (db_id), + GNUNET_PQ_query_param_end + }; + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_fixed_size ("challenge_data", + challenge_hash, + sizeof (*challenge_hash)), + GNUNET_PQ_result_spec_end + }; + + check_connection (pg); + GNUNET_break (GNUNET_OK == postgres_preflight (pg)); + + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "auth_hash_select", + params, + rs); +} + + +/** + * FIXME +*/ +static enum GNUNET_DB_QueryStatus +postgres_get_key_data ( + void *cls, + const struct FROST_HashCode *db_id, + uint32_t *identifier, + struct FROSIX_EncryptionNonceP *nonce, + struct FROSIX_KeyDataEncrypted *enc_key_data) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (db_id), + GNUNET_PQ_query_param_end + }; + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint32 ("identifier", + identifier), + GNUNET_PQ_result_spec_fixed_size ("encryption_nonce", + nonce, + sizeof (*nonce)), + GNUNET_PQ_result_spec_fixed_size ("enc_key_data", + enc_key_data, + sizeof (*enc_key_data)), + GNUNET_PQ_result_spec_end + }; + + check_connection (pg); + GNUNET_break (GNUNET_OK == postgres_preflight (pg)); + + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "key_data_select", + params, + rs); +} + + +/** + * FIXME +*/ +static enum GNUNET_DB_QueryStatus +postgres_delete_key_data ( + void *cls, + const struct FROST_HashCode *db_id) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (db_id), + GNUNET_PQ_query_param_end + }; + + check_connection (pg); + GNUNET_break (GNUNET_OK == postgres_preflight (pg)); + + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "key_delete", + params); +} + + +/** + * FIXME +*/ +static enum GNUNET_DB_QueryStatus +postgres_store_commitment_seed ( + void *cls, + const struct GNUNET_HashCode *db_id, + const struct FROST_CommitmentSeed *seed) +{ + struct PostgresClosure *pg = cls; + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); + + check_connection (pg); + GNUNET_break (GNUNET_OK == + postgres_preflight (pg)); + for (unsigned int retry = 0; retry < MAX_RETRIES; retry++) + { + if (GNUNET_OK != + begin_transaction (pg, + "seed_insert")) + { + GNUNET_break (0); + return FROSIX_DB_STORE_STATUS_HARD_ERROR; + } + + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (db_id), + GNUNET_PQ_query_param_auto_from_type (seed), + GNUNET_PQ_query_param_timestamp (&now), + GNUNET_PQ_query_param_end + }; + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "seed_insert", + params); + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + rollback (pg); + return FROSIX_DB_STORE_STATUS_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + goto retry; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_break (0); + rollback (pg); + return FROSIX_DB_STORE_STATUS_HARD_ERROR; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + qs = commit_transaction (pg); + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + goto retry; + if (qs < 0) + return FROSIX_DB_STORE_STATUS_HARD_ERROR; + return FROSIX_DB_STORE_STATUS_SUCCESS; + } + } + retry: + rollback (pg); + } + return FROSIX_DB_STORE_STATUS_SOFT_ERROR; +} + + +/** + * FIXME +*/ +static enum GNUNET_DB_QueryStatus +postgres_get_and_delete_commitment_seed ( + void *cls, + const struct GNUNET_HashCode *db_id, + struct FROST_CommitmentSeed *seed) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (db_id), + GNUNET_PQ_query_param_end + }; + + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("seed", + seed), + GNUNET_PQ_result_spec_end + }; + + check_connection (pg); + GNUNET_break (GNUNET_OK == postgres_preflight (pg)); + + enum GNUNET_DB_QueryStatus qs; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "seed_select", + params, + rs); + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + return FROSIX_DB_STORE_STATUS_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + return FROSIX_DB_STORE_STATUS_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + return FROSIX_DB_STORE_STATUS_NO_RESULTS; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "seed_delete", + params); +} + + +/** + * Create a new challenge code for a given challenge identified by the challenge + * public key. The function will first check if there is already a valid code + * for this challenge present and won't insert a new one in this case. + * + * @param cls closure + * @param truth_uuid the identifier for the challenge + * @param rotation_period for how long is the code available + * @param validity_period for how long is the code available + * @param retry_counter amount of retries allowed + * @param[out] retransmission_date when to next retransmit + * @param[out] code set to the code which will be checked for later + * @return transaction status, + * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if we are out of valid tries, + * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a code is now in the DB + */ +enum GNUNET_DB_QueryStatus +postgres_create_challenge_code ( + void *cls, + const struct FROSIX_ChallengeIdP *truth_uuid, + struct GNUNET_TIME_Relative rotation_period, + struct GNUNET_TIME_Relative validity_period, + uint32_t retry_counter, + struct GNUNET_TIME_Timestamp *retransmission_date, + uint64_t *code) +{ + struct PostgresClosure *pg = cls; + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); + struct GNUNET_TIME_Timestamp expiration_date; + struct GNUNET_TIME_Absolute ex_rot; + + check_connection (pg); + expiration_date = GNUNET_TIME_relative_to_timestamp (validity_period); + ex_rot = GNUNET_TIME_absolute_subtract (now.abs_time, + rotation_period); + for (unsigned int retries = 0; retries<MAX_RETRIES; retries++) + { + if (GNUNET_OK != + begin_transaction (pg, + "create_challenge_code")) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + + { + uint32_t old_retry_counter; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (truth_uuid), + GNUNET_PQ_query_param_timestamp (&now), + GNUNET_PQ_query_param_absolute_time (&ex_rot), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint64 ("code", + code), + GNUNET_PQ_result_spec_uint32 ("retry_counter", + &old_retry_counter), + GNUNET_PQ_result_spec_timestamp ("retransmission_date", + retransmission_date), + GNUNET_PQ_result_spec_end + }; + enum GNUNET_DB_QueryStatus qs; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "challengecode_select_meta", + params, + rs); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + rollback (pg); + return qs; + case GNUNET_DB_STATUS_SOFT_ERROR: + goto retry; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "No active challenge found, creating a fresh one\n"); + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + if (0 == old_retry_counter) + { + rollback (pg); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Active challenge %llu has zero tries left, refusing to create another one\n", + (unsigned long long) *code); + return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; + } + rollback (pg); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Active challenge has %u tries left, returning old challenge %llu\n", + (unsigned int) old_retry_counter, + (unsigned long long) *code); + return qs; + } + } + + *code = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, + FROSIX_PIN_MAX_VALUE); + *retransmission_date = GNUNET_TIME_UNIT_ZERO_TS; + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (truth_uuid), + GNUNET_PQ_query_param_uint64 (code), + GNUNET_PQ_query_param_timestamp (&now), + GNUNET_PQ_query_param_timestamp (&expiration_date), + GNUNET_PQ_query_param_uint32 (&retry_counter), + GNUNET_PQ_query_param_end + }; + + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "challengecode_insert", + params); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + rollback (pg); + return GNUNET_DB_STATUS_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + goto retry; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_break (0); + rollback (pg); + return GNUNET_DB_STATUS_HARD_ERROR; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Created fresh challenge with %u tries left\n", + (unsigned int) retry_counter); + break; + } + } + qs = commit_transaction (pg); + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + goto retry; + if (qs < 0) + return qs; + return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + retry: + rollback (pg); + } + return GNUNET_DB_STATUS_SOFT_ERROR; +} + + +/** + * Closure for check_valid_code(). + */ +struct CheckValidityContext +{ + /** + * Code to check for. + */ + const struct GNUNET_HashCode *hashed_code; + + /** + * Truth we are processing. + */ + const struct FROSIX_ChallengeIdP *truth_uuid; + + /** + * Database context. + */ + struct PostgresClosure *pg; + + /** + * Set to the matching challenge code (if @e valid). + */ + uint64_t code; + + /** + * Set to true if a code matching @e hashed_code was found. + */ + bool valid; + + /** + * Set to true if a code matching @e hashed_code was set to 'satisfied' by the plugin. + */ + bool satisfied; + + /** + * Set to true if we had a database failure. + */ + bool db_failure; + +}; + + +/** + * Helper function for #postgres_verify_challenge_code(). + * To be called with the results of a SELECT statement + * that has returned @a num_results results. + * + * @param cls closure of type `struct CheckValidityContext *` + * @param result the postgres result + * @param num_results the number of results in @a result + */ +static void +check_valid_code (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct CheckValidityContext *cvc = cls; + struct PostgresClosure *pg = cvc->pg; + + for (unsigned int i = 0; i < num_results; i++) + { + uint64_t server_code; + uint8_t sat; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint64 ("code", + &server_code), + GNUNET_PQ_result_spec_auto_from_type ("satisfied", + &sat), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + cvc->db_failure = true; + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Found issued challenge %llu (client: %s)\n", + (unsigned long long) server_code, + GNUNET_h2s (cvc->hashed_code)); + { + struct GNUNET_HashCode shashed_code; + + FROSIX_hash_answer (server_code, + &shashed_code); + if (0 == + GNUNET_memcmp (&shashed_code, + cvc->hashed_code)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Challenge is valid challenge (%s)\n", + (0 != sat) ? "satisfied" : "not satisfied"); + cvc->valid = true; + cvc->code = server_code; + cvc->satisfied = (0 != sat); + } + else + { + /* count failures to prevent brute-force attacks */ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (cvc->truth_uuid), + GNUNET_PQ_query_param_uint64 (&server_code), + GNUNET_PQ_query_param_end + }; + enum GNUNET_DB_QueryStatus qs; + + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "challengecode_update_retry", + params); + if (qs <= 0) + { + GNUNET_break (0); + cvc->db_failure = true; + } + } + } + } +} + + +/** + * Verify the provided code with the code on the server. + * If the code matches the function will return with success, if the code + * does not match, the retry counter will be decreased by one. + * + * @param cls closure + * @param truth_uuid identification of the challenge which the code corresponds to + * @param hashed_code code which the user provided and wants to verify + * @param[out] code set to the original numeric code + * @param[out] satisfied set to true if the challenge is set to satisfied + * @return code validity status + */ +enum FROSIX_DB_CodeStatus +postgres_verify_challenge_code ( + void *cls, + const struct FROSIX_ChallengeIdP *truth_uuid, + const struct GNUNET_HashCode *hashed_code, + uint64_t *code, + bool *satisfied) +{ + struct PostgresClosure *pg = cls; + struct CheckValidityContext cvc = { + .truth_uuid = truth_uuid, + .hashed_code = hashed_code, + .pg = pg + }; + struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (truth_uuid), + // GNUNET_PQ_query_param_timestamp (&now), + GNUNET_PQ_query_param_end + }; + enum GNUNET_DB_QueryStatus qs; + + *satisfied = false; + check_connection (pg); + qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, + "challengecode_select", + params, + &check_valid_code, + &cvc); + if ( (qs < 0) || + (cvc.db_failure) ) + return FROSIX_DB_CODE_STATUS_HARD_ERROR; + *code = cvc.code; + if (cvc.valid) + { + *satisfied = cvc.satisfied; + return FROSIX_DB_CODE_STATUS_VALID_CODE_STORED; + } + if (0 == qs) + return FROSIX_DB_CODE_STATUS_NO_RESULTS; + return FROSIX_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH; +} + + +/** + * Remember in the database that we successfully sent a challenge. + * + * @param cls closure + * @param truth_uuid the identifier for the challenge + * @param code the challenge that was sent + */ +static enum GNUNET_DB_QueryStatus +postgres_mark_challenge_sent ( + void *cls, + const struct FROSIX_ChallengeIdP *truth_uuid, + uint64_t code) +{ + struct PostgresClosure *pg = cls; + enum GNUNET_DB_QueryStatus qs; + + check_connection (pg); + { + struct GNUNET_TIME_Timestamp now; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (truth_uuid), + GNUNET_PQ_query_param_uint64 (&code), + GNUNET_PQ_query_param_timestamp (&now), + GNUNET_PQ_query_param_end + }; + + now = GNUNET_TIME_timestamp_get (); + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "challengecode_mark_sent", + params); + if (qs <= 0) + return qs; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Marking challenge %llu as issued\n", + (unsigned long long) code); + return qs; +} + + +/** + * Function called to remove all expired codes from the database. + * + * @return transaction status + */ +enum GNUNET_DB_QueryStatus +postgres_challenge_gc (void *cls) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_TIME_Timestamp time_now = GNUNET_TIME_timestamp_get (); + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_timestamp (&time_now), + GNUNET_PQ_query_param_end + }; + + check_connection (pg); + GNUNET_break (GNUNET_OK == + postgres_preflight (pg)); + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "gc_challengecodes", + params); +} + + +/** + * Initialize Postgres database subsystem. + * + * @param cls a configuration instance + * @return NULL on error, otherwise a `struct FROSIX_DatabasePlugin` + */ +void * +libfrosix_plugin_db_postgres_init (void *cls) +{ + struct GNUNET_CONFIGURATION_Handle *cfg = cls; + struct PostgresClosure *pg; + struct FROSIX_DatabasePlugin *plugin; + + pg = GNUNET_new (struct PostgresClosure); + pg->cfg = cfg; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "taler", + "CURRENCY", + &pg->currency)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "taler", + "CURRENCY"); + GNUNET_PQ_disconnect (pg->conn); + GNUNET_free (pg); + return NULL; + } + plugin = GNUNET_new (struct FROSIX_DatabasePlugin); + plugin->cls = pg; + /* FIXME: Should this be the same? */ + plugin->connect = &postgres_preflight; + plugin->create_tables = &postgres_create_tables; + plugin->drop_tables = &postgres_drop_tables; + // plugin->gc = &postgres_gc; + plugin->preflight = &postgres_preflight; + plugin->rollback = &rollback; + plugin->start = &begin_transaction; + plugin->commit = &commit_transaction; + plugin->event_listen = &postgres_event_listen; + plugin->event_listen_cancel = &postgres_event_listen_cancel; + plugin->event_notify = &postgres_event_notify; + plugin->store_dkg_commitment = &postgres_store_dkg_commitment; + plugin->get_dkg_commitment = &postgres_get_dkg_commitment; + plugin->lookup_dkg_commitment = &postgres_lookup_dkg_commitment; + plugin->store_key = &postgres_store_key; + plugin->lookup_key = &postgres_lookup_key; + plugin->get_key_data = &postgres_get_key_data; + plugin->delete_key_data = &postgres_delete_key_data; + plugin->get_auth_hash = &postgres_get_auth_hash; + plugin->store_commitment_seed = &postgres_store_commitment_seed; + plugin->get_and_delete_commitment_seed = + &postgres_get_and_delete_commitment_seed; + plugin->create_challenge_code = &postgres_create_challenge_code; + plugin->verify_challenge_code = &postgres_verify_challenge_code; + plugin->mark_challenge_sent = &postgres_mark_challenge_sent; + plugin->challenge_gc = &postgres_challenge_gc; + return plugin; +} + + +/** + * Shutdown Postgres database subsystem. + * + * @param cls a `struct FROSIX_DB_STATUS_Plugin` + * @return NULL (always) + */ +void * +libfrosix_plugin_db_postgres_done (void *cls) +{ + struct FROSIX_DatabasePlugin *plugin = cls; + struct PostgresClosure *pg = plugin->cls; + + GNUNET_PQ_disconnect (pg->conn); + GNUNET_free (pg->currency); + GNUNET_free (pg); + GNUNET_free (plugin); + return NULL; +} + + +/* end of plugin_frosix_postgres.c */ diff --git a/src/frosixdb/versioning.sql b/src/frosixdb/versioning.sql @@ -0,0 +1,293 @@ +-- LICENSE AND COPYRIGHT +-- +-- Copyright (C) 2010 Hubert depesz Lubaczewski +-- +-- This program is distributed under the (Revised) BSD License: +-- L<http://www.opensource.org/licenses/bsd-license.php> +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions +-- are met: +-- +-- * Redistributions of source code must retain the above copyright +-- notice, this list of conditions and the following disclaimer. +-- +-- * Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- * Neither the name of Hubert depesz Lubaczewski's Organization +-- nor the names of its contributors may be used to endorse or +-- promote products derived from this software without specific +-- prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-- +-- Code origin: https://gitlab.com/depesz/Versioning/blob/master/install.versioning.sql +-- +-- +-- # NAME +-- +-- **Versioning** - simplistic take on tracking and applying changes to databases. +-- +-- # DESCRIPTION +-- +-- This project strives to provide simple way to manage changes to +-- database. +-- +-- Instead of making changes on development server, then finding +-- differences between production and development, deciding which ones +-- should be installed on production, and finding a way to install them - +-- you start with writing diffs themselves! +-- +-- # INSTALLATION +-- +-- To install versioning simply run install.versioning.sql in your database +-- (all of them: production, stage, test, devel, ...). +-- +-- # USAGE +-- +-- In your files with patches to database, put whole logic in single +-- transaction, and use \_v.\* functions - usually \_v.register_patch() at +-- least to make sure everything is OK. +-- +-- For example. Let's assume you have patch files: +-- +-- ## 0001.sql: +-- +-- ``` +-- create table users (id serial primary key, username text); +-- ``` +-- +-- ## 0002.sql: +-- +-- ``` +-- insert into users (username) values ('depesz'); +-- ``` +-- To change it to use versioning you would change the files, to this +-- state: +-- +-- 0000.sql: +-- +-- ``` +-- BEGIN; +-- select _v.register_patch('000-base', NULL, NULL); +-- create table users (id serial primary key, username text); +-- COMMIT; +-- ``` +-- +-- ## 0002.sql: +-- +-- ``` +-- BEGIN; +-- select _v.register_patch('001-users', ARRAY['000-base'], NULL); +-- insert into users (username) values ('depesz'); +-- COMMIT; +-- ``` +-- +-- This will make sure that patch 001-users can only be applied after +-- 000-base. +-- +-- # AVAILABLE FUNCTIONS +-- +-- ## \_v.register_patch( TEXT ) +-- +-- Registers named patch, or dies if it is already registered. +-- +-- Returns integer which is id of patch in \_v.patches table - only if it +-- succeeded. +-- +-- ## \_v.register_patch( TEXT, TEXT[] ) +-- +-- Same as \_v.register_patch( TEXT ), but checks is all given patches (given as +-- array in second argument) are already registered. +-- +-- ## \_v.register_patch( TEXT, TEXT[], TEXT[] ) +-- +-- Same as \_v.register_patch( TEXT, TEXT[] ), but also checks if there are no conflicts with preexisting patches. +-- +-- Third argument is array of names of patches that conflict with current one. So +-- if any of them is installed - register_patch will error out. +-- +-- ## \_v.unregister_patch( TEXT ) +-- +-- Removes information about given patch from the versioning data. +-- +-- It doesn't remove objects that were created by this patch - just removes +-- metainformation. +-- +-- ## \_v.assert_user_is_superuser() +-- +-- Make sure that current patch is being loaded by superuser. +-- +-- If it's not - it will raise exception, and break transaction. +-- +-- ## \_v.assert_user_is_not_superuser() +-- +-- Make sure that current patch is not being loaded by superuser. +-- +-- If it is - it will raise exception, and break transaction. +-- +-- ## \_v.assert_user_is_one_of(TEXT, TEXT, ... ) +-- +-- Make sure that current patch is being loaded by one of listed users. +-- +-- If ```current_user``` is not listed as one of arguments - function will raise +-- exception and break the transaction. + +BEGIN; + +-- This file adds versioning support to database it will be loaded to. +-- It requires that PL/pgSQL is already loaded - will raise exception otherwise. +-- All versioning "stuff" (tables, functions) is in "_v" schema. + +-- All functions are defined as 'RETURNS SETOF INT4' to be able to make them to RETURN literally nothing (0 rows). +-- >> RETURNS VOID<< IS similar, but it still outputs "empty line" in psql when calling. +CREATE SCHEMA IF NOT EXISTS _v; +COMMENT ON SCHEMA _v IS 'Schema for versioning data and functionality.'; + +CREATE TABLE IF NOT EXISTS _v.patches ( + patch_name TEXT PRIMARY KEY, + applied_tsz TIMESTAMPTZ NOT NULL DEFAULT now(), + applied_by TEXT NOT NULL, + requires TEXT[], + conflicts TEXT[] +); +COMMENT ON TABLE _v.patches IS 'Contains information about what patches are currently applied on database.'; +COMMENT ON COLUMN _v.patches.patch_name IS 'Name of patch, has to be unique for every patch.'; +COMMENT ON COLUMN _v.patches.applied_tsz IS 'When the patch was applied.'; +COMMENT ON COLUMN _v.patches.applied_by IS 'Who applied this patch (PostgreSQL username)'; +COMMENT ON COLUMN _v.patches.requires IS 'List of patches that are required for given patch.'; +COMMENT ON COLUMN _v.patches.conflicts IS 'List of patches that conflict with given patch.'; + +CREATE OR REPLACE FUNCTION _v.register_patch( IN in_patch_name TEXT, IN in_requirements TEXT[], in_conflicts TEXT[], OUT versioning INT4 ) RETURNS setof INT4 AS $$ +DECLARE + t_text TEXT; + t_text_a TEXT[]; + i INT4; +BEGIN + -- Thanks to this we know only one patch will be applied at a time + LOCK TABLE _v.patches IN EXCLUSIVE MODE; + + SELECT patch_name INTO t_text FROM _v.patches WHERE patch_name = in_patch_name; + IF FOUND THEN + RAISE EXCEPTION 'Patch % is already applied!', in_patch_name; + END IF; + + t_text_a := ARRAY( SELECT patch_name FROM _v.patches WHERE patch_name = any( in_conflicts ) ); + IF array_upper( t_text_a, 1 ) IS NOT NULL THEN + RAISE EXCEPTION 'Versioning patches conflict. Conflicting patche(s) installed: %.', array_to_string( t_text_a, ', ' ); + END IF; + + IF array_upper( in_requirements, 1 ) IS NOT NULL THEN + t_text_a := '{}'; + FOR i IN array_lower( in_requirements, 1 ) .. array_upper( in_requirements, 1 ) LOOP + SELECT patch_name INTO t_text FROM _v.patches WHERE patch_name = in_requirements[i]; + IF NOT FOUND THEN + t_text_a := t_text_a || in_requirements[i]; + END IF; + END LOOP; + IF array_upper( t_text_a, 1 ) IS NOT NULL THEN + RAISE EXCEPTION 'Missing prerequisite(s): %.', array_to_string( t_text_a, ', ' ); + END IF; + END IF; + + INSERT INTO _v.patches (patch_name, applied_tsz, applied_by, requires, conflicts ) VALUES ( in_patch_name, now(), current_user, coalesce( in_requirements, '{}' ), coalesce( in_conflicts, '{}' ) ); + RETURN; +END; +$$ language plpgsql; +COMMENT ON FUNCTION _v.register_patch( TEXT, TEXT[], TEXT[] ) IS 'Function to register patches in database. Raises exception if there are conflicts, prerequisites are not installed or the migration has already been installed.'; + +CREATE OR REPLACE FUNCTION _v.register_patch( TEXT, TEXT[] ) RETURNS setof INT4 AS $$ + SELECT _v.register_patch( $1, $2, NULL ); +$$ language sql; +COMMENT ON FUNCTION _v.register_patch( TEXT, TEXT[] ) IS 'Wrapper to allow registration of patches without conflicts.'; +CREATE OR REPLACE FUNCTION _v.register_patch( TEXT ) RETURNS setof INT4 AS $$ + SELECT _v.register_patch( $1, NULL, NULL ); +$$ language sql; +COMMENT ON FUNCTION _v.register_patch( TEXT ) IS 'Wrapper to allow registration of patches without requirements and conflicts.'; + +CREATE OR REPLACE FUNCTION _v.unregister_patch( IN in_patch_name TEXT, OUT versioning INT4 ) RETURNS setof INT4 AS $$ +DECLARE + i INT4; + t_text_a TEXT[]; +BEGIN + -- Thanks to this we know only one patch will be applied at a time + LOCK TABLE _v.patches IN EXCLUSIVE MODE; + + t_text_a := ARRAY( SELECT patch_name FROM _v.patches WHERE in_patch_name = ANY( requires ) ); + IF array_upper( t_text_a, 1 ) IS NOT NULL THEN + RAISE EXCEPTION 'Cannot uninstall %, as it is required by: %.', in_patch_name, array_to_string( t_text_a, ', ' ); + END IF; + + DELETE FROM _v.patches WHERE patch_name = in_patch_name; + GET DIAGNOSTICS i = ROW_COUNT; + IF i < 1 THEN + RAISE EXCEPTION 'Patch % is not installed, so it can''t be uninstalled!', in_patch_name; + END IF; + + RETURN; +END; +$$ language plpgsql; +COMMENT ON FUNCTION _v.unregister_patch( TEXT ) IS 'Function to unregister patches in database. Dies if the patch is not registered, or if unregistering it would break dependencies.'; + +CREATE OR REPLACE FUNCTION _v.assert_patch_is_applied( IN in_patch_name TEXT ) RETURNS TEXT as $$ +DECLARE + t_text TEXT; +BEGIN + SELECT patch_name INTO t_text FROM _v.patches WHERE patch_name = in_patch_name; + IF NOT FOUND THEN + RAISE EXCEPTION 'Patch % is not applied!', in_patch_name; + END IF; + RETURN format('Patch %s is applied.', in_patch_name); +END; +$$ language plpgsql; +COMMENT ON FUNCTION _v.assert_patch_is_applied( TEXT ) IS 'Function that can be used to make sure that patch has been applied.'; + +CREATE OR REPLACE FUNCTION _v.assert_user_is_superuser() RETURNS TEXT as $$ +DECLARE + v_super bool; +BEGIN + SELECT usesuper INTO v_super FROM pg_user WHERE usename = current_user; + IF v_super THEN + RETURN 'assert_user_is_superuser: OK'; + END IF; + RAISE EXCEPTION 'Current user is not superuser - cannot continue.'; +END; +$$ language plpgsql; +COMMENT ON FUNCTION _v.assert_user_is_superuser() IS 'Function that can be used to make sure that patch is being applied using superuser account.'; + +CREATE OR REPLACE FUNCTION _v.assert_user_is_not_superuser() RETURNS TEXT as $$ +DECLARE + v_super bool; +BEGIN + SELECT usesuper INTO v_super FROM pg_user WHERE usename = current_user; + IF v_super THEN + RAISE EXCEPTION 'Current user is superuser - cannot continue.'; + END IF; + RETURN 'assert_user_is_not_superuser: OK'; +END; +$$ language plpgsql; +COMMENT ON FUNCTION _v.assert_user_is_not_superuser() IS 'Function that can be used to make sure that patch is being applied using normal (not superuser) account.'; + +CREATE OR REPLACE FUNCTION _v.assert_user_is_one_of(VARIADIC p_acceptable_users TEXT[] ) RETURNS TEXT as $$ +DECLARE +BEGIN + IF current_user = any( p_acceptable_users ) THEN + RETURN 'assert_user_is_one_of: OK'; + END IF; + RAISE EXCEPTION 'User is not one of: % - cannot continue.', p_acceptable_users; +END; +$$ language plpgsql; +COMMENT ON FUNCTION _v.assert_user_is_one_of(TEXT[]) IS 'Function that can be used to make sure that patch is being applied by one of defined users.'; + +COMMIT; diff --git a/src/include/Makefile.am b/src/include/Makefile.am @@ -0,0 +1,19 @@ +# This Makefile.am is in the public domain + +frostincludedir = $(includedir)/frost + +frostinclude_HEADERS = \ + frosix.h \ + frosix_crypto.h \ + frosix_backend.h \ + frosix_authorization_lib.h \ + frosix_authorization_plugin.h \ + frosix_database_lib.h \ + frosix_database_plugin.h \ + frosix_service.h \ + frosix_util_lib.h \ + platform.h gettext.h \ + frost_low.h \ + frost_high.h \ + frost_verify.h \ + keygen.h diff --git a/src/include/frosix.h b/src/include/frosix.h @@ -0,0 +1,147 @@ +/* + This file is part of Frosix + Copyright (C) 2020, 2021 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/frosix.h + * @brief frosix client api + * @author Christian Grothoff + * @author Dominik Meister + * @author Dennis Neufeld + * @author Joel Urech + */ +#ifndef FROSIX_H +#define FROSIX_H + +#include <jansson.h> +#include "frosix_backend.h" +#include "frosix_service.h" +#include <taler/taler_mhd_lib.h> +#include <regex.h> + + +/** + * Initialize reducer subsystem. + * + * @param ctx context to use for CURL requests. + */ +void +FROSIX_redux_init (struct GNUNET_CURL_Context *ctx); + + +/** + * Signature of the callback passed to #FROSIX_redux_action() + * + * @param cls closure + * @param error error code, #TALER_EC_NONE if @a new_bs is the new successful state + * @param new_state the new state of the operation (client should json_incref() to keep an alias) + */ +typedef void +(*FROSIX_ActionCallback)(void *cls, + enum TALER_ErrorCode error, + json_t *new_state); + + +/** + * Generic container for an action with asynchronous activities. + * Handle to an ongoing action. Only valid until the #FROSIX_ActionCallback is invoked. + */ +struct FROSIX_ReduxAction +{ + /** + * Function to call to clean up. + */ + void (*cleanup)(void *cls); + + /** + * Action-specific state, closure for @e cleanup. + */ + void *cleanup_cls; +}; + + + +/** + * Cancel ongoing redux action. + * + * @param ra action to cancel + */ +void +FROSIX_redux_action_cancel (struct FROSIX_ReduxAction *ra); + + +/** + * FIXME +*/ +struct FROSIX_ReduxAction * +FROSIX_redux_keygen_start (const json_t *arguments, + FROSIX_ActionCallback cb, + void *cb_cls); + + +/** + * FIXME +*/ +struct FROSIX_ReduxAction * +FROSIX_redux_challenge_request_start (const json_t *arguments, + const json_t *input, + const char *message, + FROSIX_ActionCallback cb, + void *cb_cls); + + +/** + * FIXME +*/ +struct FROSIX_ReduxAction * +FROSIX_redux_sign_start (const json_t *arguments, + json_t *input, + const char *message, + FROSIX_ActionCallback cb, + void *cb_cls); + + +/** + * FIXME +*/ +struct FROSIX_ReduxAction * +FROSIX_redux_key_delete_start (json_t *input, + FROSIX_ActionCallback cb, + void *cb_cls); + + +/** + * FIXME +*/ +enum GNUNET_GenericReturnValue +FROSIX_verify_signature (const char *message, + const json_t *arguments); + + +/** + * FIXME +*/ +void +FROSIX_export_public_key (const json_t *arguments, + FROSIX_ActionCallback cb, + void *cb_cls); + + +/** + * FIXME +*/ +enum GNUNET_GenericReturnValue +FROSIX_verify_public_key (const json_t *arguments); + +#endif /* _FROSIX_REDUX_H */ diff --git a/src/include/frosix_authorization_lib.h b/src/include/frosix_authorization_lib.h @@ -0,0 +1,50 @@ +/* + This file is part of Frosix + Copyright (C) 2019, 2021 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/frosix_authorization_lib.h + * @brief database plugin loader + * @author Dominik Meister + * @author Dennis Neufeld + * @author Christian Grothoff + */ +#ifndef FROSIX_AUTHORIZATION_LIB_H +#define FROSIX_AUTHORIZATION_LIB_H + +#include "frosix_authorization_plugin.h" + +/** + * Load authorization plugin. + * + * @param method name of the method to load + * @param db database handle to use + * @param FH_cfg configuration to use + * @return plugin handle on success + */ +struct FROSIX_AuthorizationPlugin * +FROSIX_authorization_plugin_load ( + const char *method, + struct FROSIX_DatabasePlugin *db, + const struct GNUNET_CONFIGURATION_Handle *FH_cfg); + + +/** + * Shutdown all loaded plugins. + */ +void +FROSIX_authorization_plugin_shutdown (void); + +#endif +/* end of frosix_authorization_lib.h */ diff --git a/src/include/frosix_authorization_plugin.h b/src/include/frosix_authorization_plugin.h @@ -0,0 +1,280 @@ +/* + This file is part of Frosix + Copyright (C) 2019 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/frosix_authorization_plugin.h + * @brief authorization access for Frosix + * @author Christian Grothoff + */ +#ifndef FROSIX_AUTHORIZATION_PLUGIN_H +#define FROSIX_AUTHORIZATION_PLUGIN_H + +#include "frosix_service.h" +#include <taler/taler_util.h> + + +/** + * Plugin-specific state for an authorization operation. + */ +struct FROSIX_AUTHORIZATION_State; + + +/** + * Enumeration values indicating the various possible + * outcomes of the plugin's `challenge` function. + */ +enum FROSIX_AUTHORIZATION_ChallengeResult +{ + /** + * We successfully sent the authorization challenge + * and queued a reply to MHD. + */ + FROSIX_AUTHORIZATION_CRES_SUCCESS = 0, + + /** + * We failed to transmit the authorization challenge, + * but successfully queued a failure response to MHD. + */ + FROSIX_AUTHORIZATION_CRES_FAILED = 1, + + /** + * The plugin suspended the MHD connection as it needs some more + * time to do its (asynchronous) work before we can proceed. The + * plugin will resume the MHD connection when its work is done, and + * then the `process` function should be called again. + */ + FROSIX_AUTHORIZATION_CRES_SUSPENDED = 2, + + /** + * The plugin tried to queue a reply on the MHD connection and + * failed to do so. We should return #MHD_NO to MHD to cause the + * HTTP connection to be closed without any reply. + * + * However, we were successful at transmitting the challenge, + * so the challenge should be marked as sent. + */ + FROSIX_AUTHORIZATION_CRES_SUCCESS_REPLY_FAILED = 4, + + /** + * The plugin tried to queue a reply on the MHD connection and + * failed to do so. We should return #MHD_NO to MHD to cause the + * HTTP connection to be closed without any reply. + * + * Additionally, we failed to transmit the challenge. + */ + FROSIX_AUTHORIZATION_CRES_FAILED_REPLY_FAILED = 5 +}; + + +/** + * Enumeration values indicating the various possible + * outcomes of the plugin's `solve` function. + */ +enum FROSIX_AUTHORIZATION_SolveResult +{ + /** + * We failed to transmit the authorization challenge, + * but successfully queued a failure response to MHD. + */ + FROSIX_AUTHORIZATION_SRES_FAILED = 0, + + /** + * The plugin suspended the MHD connection as it needs some more + * time to do its (asynchronous) work before we can proceed. The + * plugin will resume the MHD connection when its work is done, and + * then the `process` function should be called again. + */ + FROSIX_AUTHORIZATION_SRES_SUSPENDED = 1, + + /** + * The plugin tried to queue a reply on the MHD connection and + * failed to do so. We should return #MHD_NO to MHD to cause the + * HTTP connection to be closed without any reply. + * + * Additionally, we failed to transmit the challenge. + */ + FROSIX_AUTHORIZATION_SRES_FAILED_REPLY_FAILED = 2, + + /** + * The authentication process completed successfully + * and we should signal success to the client by + * returning the truth. + */ + FROSIX_AUTHORIZATION_SRES_FINISHED = 3 +}; + + +/** + * Argument passed to the "init" function of each + * plugin. + */ +struct FROSIX_AuthorizationContext +{ + /** + * Database handle. + */ + struct FROSIX_DatabasePlugin *db; + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; +}; + + +/** + * Handle to interact with a authorization backend. + */ +struct FROSIX_AuthorizationPlugin +{ + + /** + * Closure for all callbacks. + */ + void *cls; + + /** + * Cost to GET the /truth using this method. Set by the plugin's + * loader, not by the plugin itself. + */ + struct TALER_Amount cost; + + /** + * True if the payment is managed internally by the + * authorization plugin. + */ + bool payment_plugin_managed; + + /** + * The plugin expects the "code" in the "start" function to be + * provided by the user and not generated by the Frosix + * backend. The plugin will then validate the code using its own + * means. Used by TOTP. + */ + bool user_provided_code; + + /** + * How often are retries allowed for challenges created + * by this plugin? + */ + uint32_t retry_counter; + + /** + * How long should a generated challenge be valid for this type of method. + */ + struct GNUNET_TIME_Relative code_validity_period; + + /** + * How long before we should rotate a challenge for this type of method. + */ + struct GNUNET_TIME_Relative code_rotation_period; + + /** + * How long before we should retransmit a code. + */ + struct GNUNET_TIME_Relative code_retransmission_frequency; + + /** + * Validate @a data is a well-formed input into the challenge method, + * i.e. @a data is a well-formed phone number for sending an SMS, or + * a well-formed e-mail address for sending an e-mail. Not expected to + * check that the phone number or e-mail account actually exists. + * + * To be possibly used before issuing a 402 payment required to the client. + * + * @param cls closure + * @param connection HTTP client request (for queuing response) + * @param truth_mime mime type of @e data + * @param data input to validate (i.e. is it a valid phone number, etc.) + * @param data_length number of bytes in @a data + * @return #GNUNET_OK if @a data is valid, + * #GNUNET_NO if @a data is invalid and a reply was successfully queued on @a connection + * #GNUNET_SYSERR if @a data invalid but we failed to queue a reply on @a connection + */ + enum GNUNET_GenericReturnValue + (*validate)(void *cls, + struct MHD_Connection *connection, + const char *truth_mime, + const char *data, + size_t data_length); + + + /** + * Begin issuing authentication challenge to user based on @a data. + * I.e. start to send SMS or e-mail or launch video identification, + * or at least setup our authorization state (actual processing + * may also be startedin the @e process function). + * + * @param cls closure + * @param trigger function to call when we made progress + * @param trigger_cls closure for @a trigger + * @param truth_public_key Identifier of the challenge, to be (if possible) included in the + * interaction with the user + * @param code secret code that the user has to provide back to satisfy the challenge in + * the main anastasis protocol + * @param auth_command authentication command which is executed + * @param data input to validate (i.e. is it a valid phone number, etc.) + * @return state to track progress on the authorization operation, NULL on failure + */ + struct FROSIX_AUTHORIZATION_State * + (*start)(void *cls, + GNUNET_SCHEDULER_TaskCallback trigger, + void *trigger_cls, + const struct FROSIX_ChallengeIdP *truth_public_key, + uint64_t code, + const void *data, + size_t data_length); + + + /** + * Continue issuing authentication challenge to user based on @a data. + * I.e. check if the transmission of the challenge via SMS or e-mail + * has completed and/or manipulate @a connection to direct the client towards solving the challenge. + * + * @param as authorization state + * @param connection HTTP client request (for queuing response, such as redirection to video portal) + * @return state of the request + */ + enum FROSIX_AUTHORIZATION_ChallengeResult + (*challenge)(struct FROSIX_AUTHORIZATION_State *as, + struct MHD_Connection *connection); + + + /** + * Check if the client has solved the challenge. + * + * @param as authorization state + * @param timeout how long do we have to produce a reply + * @param challenge_response hash of the challenge response, or NULL + * @param connection HTTP client request (for queuing response, such as redirection to video portal) + * @return state of the request + */ + enum FROSIX_AUTHORIZATION_SolveResult + (*solve)(struct FROSIX_AUTHORIZATION_State *as, + struct GNUNET_TIME_Absolute timeout, + const struct FROST_HashCode *challenge_response, + struct MHD_Connection *connection); + + + /** + * Free internal state associated with @a as. + * + * @param as state to clean up + */ + void + (*cleanup)(struct FROSIX_AUTHORIZATION_State *as); + +}; +#endif diff --git a/src/include/frosix_backend.h b/src/include/frosix_backend.h @@ -0,0 +1,256 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Frosix + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/frost_high.h + * @brief frosix high level api to create a signature share + * @author Joel Urech +*/ +#ifndef FROSIX_BACKEND_H +#define FROSIX_BACKEND_H + +#include <gnunet/gnunet_util_lib.h> +#include "frost_low.h" +#include "frosix.h" + +/** + * Server to client: this is the policy version. + */ +// #define FROSIX_HTTP_HEADER_POLICY_VERSION "Frosix-Version" + +/** + * Server to client: this is the policy expiration time. + */ +// #define ANASTASIS_HTTP_HEADER_POLICY_EXPIRATION "Anastasis-Policy-Expiration" + +/** + * Client to server: use this to decrypt the truth. + */ +/*#define ANASTASIS_HTTP_HEADER_TRUTH_DECRYPTION_KEY \ + "Anastasis-Truth-Decryption-Key"*/ + +/** + * Client to server: please store this meta data. + */ +// #define ANASTASIS_HTTP_HEADER_POLICY_META_DATA "Anastasis-Policy-Meta-Data" + + +/** + * Client to server: I paid using this payment secret. + */ +// #define ANASTASIS_HTTP_HEADER_PAYMENT_IDENTIFIER +// "Anastasis-Payment-Identifier" + +/** + * Client to server: I am authorized to update this policy, or + * server to client: I prove this is a valid policy. + */ +// #define ANASTASIS_HTTP_HEADER_POLICY_SIGNATURE "Anastasis-Policy-Signature" + +/** + * Server to client: Taler Payto-URI. + */ +// #define ANASTASIS_HTTP_HEADER_TALER "Taler" + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * An EdDSA public key that is used to identify a user's account. + */ +/*struct FROSIX_CRYPTO_AccountPublicKeyP +{ + struct GNUNET_CRYPTO_EddsaPublicKey pub; +};*/ + + +/** + * An EdDSA private key that is used to identify a user's account. + */ +/*struct ANASTASIS_CRYPTO_AccountPrivateKeyP +{ + struct GNUNET_CRYPTO_EddsaPrivateKey priv; +};*/ + + +/** + * Specifies a TruthKey which is used to decrypt the Truth stored by the user. + */ +/*struct ANASTASIS_CRYPTO_TruthKeyP +{ + struct FROST_HashCode key; +};*/ + + +/** + * Specifies a salt value used to encrypt the master public key. + */ +/*struct ANASTASIS_CRYPTO_MasterSaltP +{ + struct FROST_HashCode salt; +};*/ + + + + + +/** + * Specifies a policy key which is used to decrypt the master key + */ +/*struct ANASTASIS_CRYPTO_PolicyKeyP +{ + struct FROST_HashCode key; +};*/ + + +/** + * Nonce used for encryption, 24 bytes. + */ +/*struct ANASTASIS_CRYPTO_NonceP +{ + uint8_t nonce[crypto_secretbox_NONCEBYTES]; +};*/ + + +/** + * Header that is prepended to a ciphertext, consisting of nonce and MAC. + */ +/*struct ANASTASIS_CRYPTO_CiphertextHeaderP +{ + uint8_t header[crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES]; +};*/ + + +/** + * Specifies a key used for symmetric encryption, 32 bytes. + */ +/*struct ANASTASIS_CRYPTO_SymKeyP +{ + uint32_t key[8]; +};*/ + + +/** + * Specifies a Key Share from an escrow provider, the combined + * keyshares generate the EscrowMasterKey which is used to decrypt the + * Secret from the user. + */ +/*struct ANASTASIS_CRYPTO_KeyShareP +{ + uint32_t key[8]; +};*/ + + +/** + * Specifies an encrypted KeyShare + */ +/*struct FROSIX_CRYPTO_EncryptedKeyShareP +{ + // + * Ciphertext. + // + struct ANASTASIS_CRYPTO_CiphertextHeaderP header; + + // + * The actual key share, encrypted. + // + struct ANASTASIS_CRYPTO_KeyShareP keyshare; +};*/ + + +/** + * The escrow master key is the key used to encrypt the user secret (MasterKey). + */ +/*struct ANASTASIS_CRYPTO_EscrowMasterKeyP +{ + uint32_t key[8]; +};*/ + + +/** + * The user identifier consists of user information and the server salt. It is used as + * entropy source to generate the account public key and the encryption keys. + */ +/*struct ANASTASIS_CRYPTO_UserIdentifierP +{ + struct FROST_HashCode hash; +};*/ + + + + + +/** + * Data signed by the account public key of a sync client to + * authorize the upload of the backup. + */ +/* struct ANASTASIS_UploadSignaturePS +{ + // + * Set to #TALER_SIGNATURE_ANASTASIS_POLICY_UPLOAD. + // + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + // + * Hash of the new backup. + // + struct FROST_HashCode new_recovery_data_hash; + +}; */ + + +/** + * Signature made with an account's public key. + */ +/*struct FROSIX_AccountSignatureP +{*/ +/** + * We use EdDSA. + */ +/*struct GNUNET_CRYPTO_EddsaSignature eddsa_sig; +};*/ + + + GNUNET_NETWORK_STRUCT_END + +/** + * Result of encrypting the core secret. + */ +// struct ANASTASIS_CoreSecretEncryptionResult +// { +/** + * Encrypted core secret. + */ +// void *enc_core_secret; + +/** + * Size of the encrypted core secret. + */ +// size_t enc_core_secret_size; + +/** + * Array of encrypted master keys. Each key is encrypted + * to a different policy key. + */ +// void **enc_master_keys; + +/** + * Sizes of the encrypted master keys. + */ +// size_t *enc_master_key_sizes; +// }; + + +#endif +\ No newline at end of file diff --git a/src/include/frosix_crypto.h b/src/include/frosix_crypto.h @@ -0,0 +1,438 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/frosix_crypto.h + * @brief frosix crypto functions + * @author Joel Urech + */ +#ifndef FROSIX_CRYPTO_H +#define FROSIX_CRYPTO_H + +#include "frost_low.h" +#include "frost_high.h" +#include <sodium.h> +#include <taler/taler_json_lib.h> +#include <gnunet/gnunet_util_lib.h> +#include <stdbool.h> + + +/*** Frosix Crypto ***/ + +/** + * This encryption key is used to encrypt and decrypt the key data stored + * in the provider's database. The encryption key itself is not stored in + * the database and is only saved in the `Frosix Sign Document`. +*/ +struct FROSIX_EncryptionKey +{ + unsigned char bytes[crypto_secretbox_KEYBYTES]; +}; + + +/** + * Random nonce for the encryption of the key data stored in the provider's + * database. This nonce is also stored in the database. +*/ +struct FROSIX_EncryptionNonceP +{ + unsigned char bytes[crypto_secretbox_NONCEBYTES]; +}; + + +/** + * Used in Frosix DKG to transmit the secret shares from all providers + * to all providers, without letting the client know what the secret share is. +*/ +struct FROSIX_EncryptedShareP +{ + unsigned char bytes[FROST_SCALAR_BYTES]; +}; + + +/** + * An ID which is used to identify a challenge. + */ +struct FROSIX_ChallengeIdP +{ + struct GNUNET_HashCode hash; +}; + + +/** + * High entropy context string, used in Frosix DKG as seed + * to derive the commitment. +*/ +struct FROSIX_DkgContextStringP +{ + struct FROST_HashCode hash; // FIXME +}; + + +/** + * Hashed authentication data, stored in the provider's database. + * Used to verify the submitted challenge data in order to issue + * a challenge code. +*/ +struct FROSIX_ChallengeHashP +{ + struct GNUNET_HashCode hash; +}; + + +/** + * Specifies a salt value provided by an Frosix provider as result + * of an /config request, used for deriving the encryption key, + * the challenge nonce and is part of the Frosix DKG request id. + */ +struct FROSIX_ProviderSaltP +{ + struct GNUNET_CRYPTO_PowSalt salt; +}; + + +/** + * Specifies a nonce, used for salting the hash of the authentication data. + */ +struct FROSIX_ChallengeNonce +{ + struct GNUNET_HashCode hash; +}; + + +/** + * Secret long term source of high entropy of every provider, which is included + * before deriving the commitment in Frosix DKG. +*/ +struct FROSIX_SecretProviderSaltP +{ + struct GNUNET_CRYPTO_PowSalt salt; +}; + + +/** + * Provides a struct to sign the result of a Frosix DKG with the providers + * secret signing key. +*/ +struct FROSIX_DkgKeySignaturePS +{ + /** + * Should contain a GNUNET_SIGNATURE_PURPOSE_XXX, + * has `htonl (104)` at the moment. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * The signature is over the resulting public key and... + */ + struct FROST_PublicKey public_key; + + /** + * ... the submitted salted authentication hash. + */ + struct FROSIX_ChallengeHashP auth_hash; +}; + +/** + * Provides a struct to sign the message with from the security question + * derived secret signing key. +*/ +struct FROSIX_AuthSignaturePS +{ + /** + * Should contain a GNUNET_SIGNATURE_PURPOSE_XXX, + * has `htonl (104)` at the moment. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * The signature is over the hash of the message + */ + struct FROST_MessageHash mh; +}; + + +/*** Frosix DKG ***/ + +/** + * Deterministically derived identifier of a HTTP POST request in Frosix DKG, + * transmitted in the URL. The provider has to prove this id against the + * submitted data in the POST request body. +*/ +struct FROSIX_DkgRequestIdP +{ + struct FROST_HashCode id; // FIXME +}; + + +/*** Frosix Sign ***/ + +/** + * Deterministically derived identifier of a HTTP POST request in FROSIX Sign, + * transmitted in the URL. The provider has to prove this id against the + * submitted data in the POST request body. +*/ +struct FROSIX_SigRequestIdP +{ + struct FROST_HashCode id; // FIXME +}; + + +/*** Frosix Challenge ***/ + +/** + * Deterministically derived identifier of a HTTP POST request in + * FROSIX Challenge, transmitted in the URL. The provider has to prove this id + * against the submitted data in the POST request body. +*/ +struct FROSIX_ChallengeRequestIdP +{ + struct FROST_HashCode id; // FIXME +}; + + +/*** Frosix Database ***/ + +/** + * Just a pointer and the number of bytes at the pointers target. + * Is used in Frosix DKG, while storing all other provider's commitment, + * to copy all commitments at one place in memory. + * This struct is also used to load the commitments from the database and copy + * each commitment back in a useful struct. +*/ +struct FROSIX_DkgCommitmentsRaw +{ + void *ptr_commits; + size_t length; +}; + + +/** + * Byte array including the secret and the public key, before an encryption + * or right after a decryption. +*/ +struct FROSIX_KeyDataRaw +{ + unsigned char bytes[FROST_POINT_BYTES + FROST_SCALAR_BYTES]; +}; + + +/** + * Byte array for the encrypted key data before storing in the database + * or to load from the database. +*/ +struct FROSIX_KeyDataEncrypted +{ + unsigned char bytes[crypto_secretbox_MACBYTES + + sizeof (struct FROSIX_KeyDataRaw)]; +}; + + +/*** Frosix Payment - not implemented yet ***/ + +/** + * Random identifier used to later charge a payment. + */ +struct FROSIX_PaymentSecretP +{ + uint32_t id[8]; +}; + + +/** + * Encrypts the key data in a FROSIX DKG to store them + * in the providers database. + * + * @param[out] ciphertext The encrypted data + * @param[in] plaintext Plaintext data to encrypt + * @param[in] nonce Nonce value to use in the symmetric encryption + * @param[in] key The encryption key + * @return #GNUNET_OK if the encryption was successful + * #GNUNET_NO if there was a problem while encrypting +*/ +enum GNUNET_GenericReturnValue +FROSIX_secretbox_keydata (struct FROSIX_KeyDataEncrypted *ciphertext, + const struct FROSIX_KeyDataRaw *plaintext, + const struct FROSIX_EncryptionNonceP *nonce, + const struct FROSIX_EncryptionKey *key); + + +/** + * Decrypts encrypted key data from the providers database in Frosix Sign. + * + * @param[out] plaintext The resulting plaintext + * @param[in] ciphertext Encrypted data to decrypt + * @param[in] nonce Nonce value used in the symmetric encryption + * @param[in] key Key which was used to encrypt the data in @e ciphertext + * @return #GNUNET_OK if the decryption was successful + * #GNUNET_NO otherwise +*/ +enum GNUNET_GenericReturnValue +FROSIX_secretbox_keydata_open ( + struct FROSIX_KeyDataRaw *plaintext, + const struct FROSIX_KeyDataEncrypted *ciphertext, + const struct FROSIX_EncryptionNonceP *nonce, + const struct FROSIX_EncryptionKey *key); + + +/** + * Returns a high entropy nonce to be used in FROSIX_secretbox_keydata. + * + * @param[out] nonce The resulting nonce value +*/ +void +FROSIX_secretbox_nonce_randombytes (struct FROSIX_EncryptionNonceP *nonce); + + +/** + * Returns the hash of an encryption key. This hash is used as identifier + * in the providers databases. + * + * @param[out] enc_key_hash Hash of the encryption key + * @param[in] enc_key Encryption key to hash +*/ +void +FROSIX_hash_encryption_key (struct FROST_HashCode *enc_key_hash, // FIXME + const struct FROSIX_EncryptionKey *enc_key); + + +/** + * Returns the authentication hash, derived from the submitted + * authentication data and the authentication nonce. + * + * @param[out] auth_hash Resulting authentication hash + * @param[in] auth_data Null-terminated string, containing + * the authentication data + * @param[in] auth_nonce Nonce value which should be used to salt + * the resulting hash +*/ +void +FROSIX_compute_auth_hash (struct FROSIX_ChallengeHashP *auth_hash, + const char *auth_data, + const struct GNUNET_HashCode *auth_nonce); + + +/** + * Computes the id of a POST request to /auth-challenge. + * + * @param[out] request_id The resulting request id + * @param[in] enc_key Encryption key -> FIXME Should be hash of enc key + * @param[in] message_hash Hash of message or plaintext message -> FIXME +*/ +void +FROSIX_compute_challenge_request_id ( + struct FROSIX_ChallengeRequestIdP *request_id, + const struct FROSIX_EncryptionKey *enc_key, + const struct FROST_MessageHash *message_hash); + + +/** + * Computes the id of a POST request to /sig-commitment and /sig-share. + * + * @param[out] request_id The resulting request id + * @param[in] enc_key_hash Hash of the encryption key, which was used to$ + * encrypt the data stored at the provider + * @param[in] message_hash Hash of message or plaintext message -> FIXME +*/ +void +FROSIX_compute_signature_request_id ( + struct FROSIX_SigRequestIdP *request_id, + const struct FROST_HashCode *enc_key_hash, + const struct FROST_MessageHash *message_hash); + + +/** + * Computes the id of a POST request to /dkg-commitment, /dkg-share + * and /dkg-key. + * + * @param[out] request_id The resulting request id + * @param[in] context_string Main source of entropy for the provider + * @param[in] challenge_hash Salted hash of the authentication data + * @param[in] provider_salt Salt value which we received from a /config request + * @param[in] provider_index Index of the provider in this Frosix DKG + * @param[in] num_of_participants Number of participating providers + * @param[in] threshold Chosen threshold value for this Frosix DKG +*/ +void +FROSIX_compute_dkg_request_id ( + struct FROSIX_DkgRequestIdP *request_id, + const struct FROSIX_DkgContextStringP *context_string, + const struct FROSIX_ChallengeHashP *challenge_hash, + const struct FROSIX_ProviderSaltP *provider_salt, + uint8_t provider_index, + uint8_t num_of_participants, + uint8_t threshold); + + +/** + * Computes an id which is used as identifier to store the challenge + * in the database. -> FIXME should not be in frosix.h + * + * @param[out] challenge_id The resulting request id + * @param[in] enc_key_hash Identifier of the corresponding auth data + * @param[in] mh Hash of the message, to bind a request to a specific message +*/ +void +FROSIX_compute_challenge_id (struct FROSIX_ChallengeIdP *challenge_id, + const struct FROST_HashCode *enc_key_hash, // FIXME + const struct FROST_MessageHash *mh); + + +/** + * Compares two given `struct GNUNET_HashCode`s. + * + * @param[in] hc1 First hash to compare + * @param[in] hc2 Second hash to compare + * @return #GNUNET_OK if the hashes matches + * #GNUNET_NO otherwise +*/ +enum GNUNET_GenericReturnValue +FROSIX_gnunet_hash_cmp (const struct GNUNET_HashCode *hc1, + const struct GNUNET_HashCode *hc2); + + +/** + * Hash a numerical answer to compute the hash value to be submitted + * to the server for verification. Useful for PINs and SMS-TANs and + * other numbers submitted for challenges. + * + * @param code the numeric value to hash + * @param[out] hashed_code the resulting hash value to submit to the Frosix server + */ +void +FROSIX_hash_answer (uint64_t code, + struct GNUNET_HashCode *hashed_code); + + +/** + * FIXME + */ +void +FROSIX_nonce_to_pow_salt (struct FROST_PowSalt *salt, + const struct GNUNET_HashCode *nonce); + + +/** + * FIXME +*/ +void +FROSIX_hash_pow (struct GNUNET_HashCode *hash, + struct GNUNET_CRYPTO_Edx25519PrivateKey *priv, + struct GNUNET_CRYPTO_Edx25519PublicKey *pub, + const struct GNUNET_HashCode *nonce, + const char *auth_answer, + unsigned int amplifier); + +#endif +\ No newline at end of file diff --git a/src/include/frosix_database_lib.h b/src/include/frosix_database_lib.h @@ -0,0 +1,49 @@ +/* + This file is part of Frosix + Copyright (C) 2019 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/frosix_database_lib.h + * @brief database plugin loader + * @author Dominik Meister + * @author Dennis Neufeld + * @author Christian Grothoff + */ +#ifndef FROSIX_DB_LIB_H +#define FROSIX_DB_LIB_H + +#include "frosix_database_plugin.h" + +/** + * Initialize the plugin. + * + * @param cfg configuration to use + * @return NULL on failure + */ +struct FROSIX_DatabasePlugin * +FROSIX_DB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Shutdown the plugin. + * + * @param plugin plugin to unload + */ +void +FROSIX_DB_plugin_unload (struct FROSIX_DatabasePlugin *plugin); + + +#endif + +/* end of frosix_database_lib.h */ diff --git a/src/include/frosix_database_plugin.h b/src/include/frosix_database_plugin.h @@ -0,0 +1,736 @@ +/* + This file is part of Frosix + Copyright (C) 2019-2022 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/frosix_database_plugin.h + * @brief database access for Frosix + * @author Christian Grothoff + */ +#ifndef FROSIX_DATABASE_PLUGIN_H +#define FROSIX_DATABASE_PLUGIN_H + +#include "frosix_service.h" +#include "frost_high.h" +#include "keygen.h" +#include "frosix_util_lib.h" +#include <gnunet/gnunet_db_lib.h> +#include <taler/taler_util.h> + +/** + * How long is an offer for a challenge payment valid for payment? + */ +#define FROSIX_CHALLENGE_OFFER_LIFETIME GNUNET_TIME_UNIT_HOURS + +/** + * FIXME +*/ +enum FROSIX_DB_CommitmentStatus +{ + /** + * FIXME + */ + FROSIX_DB_COMMITMENT_STATUS_HARD_ERROR = -2, + + /** + * FIXME + */ + FROSIX_DB_COMMITMENT_STATUS_SOFT_ERROR = -1, + + /** + * FIXME + */ + FROSIX_DB_COMMITMENT_STATUS_NO_RESULTS = 0, + + /** + * FIXME + */ + FROSIX_DB_COMMITMENT_STATUS_ONE_RESULT = 1, +}; + +/** + * FIXME +*/ +enum FROSIX_DB_KeyStatus +{ + /** + * FIXME + */ + FROSIX_DB_KEY_STATUS_HARD_ERROR = -2, + + /** + * FIXME + */ + FROSIX_DB_KEY_STATUS_SOFT_ERROR = -1, + + /** + * FIXME + */ + FROSIX_DB_KEY_STATUS_NO_RESULTS = 0, + + /** + * FIXME + */ + FROSIX_DB_KEY_STATUS_ONE_RESULT = 1, +}; + +/** + * Return values for checking code validity. + */ +enum FROSIX_DB_CodeStatus +{ + /** + * Provided authentication code does not match database content. + */ + FROSIX_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH = -3, + + /** + * Encountered hard error talking to DB. + */ + FROSIX_DB_CODE_STATUS_HARD_ERROR = -2, + + /** + * Encountered serialization error talking to DB. + */ + FROSIX_DB_CODE_STATUS_SOFT_ERROR = -1, + + /** + * We have no challenge in the database. + */ + FROSIX_DB_CODE_STATUS_NO_RESULTS = 0, + + /** + * The provided challenge matches what we have in the database. + */ + FROSIX_DB_CODE_STATUS_VALID_CODE_STORED = 1, +}; + + +/** + * Return values for checking account validity. + */ +enum FROSIX_DB_AccountStatus +{ + /** + * Account is unknown, user should pay to establish it. + */ + FROSIX_DB_ACCOUNT_STATUS_PAYMENT_REQUIRED = -3, + + /** + * Encountered hard error talking to DB. + */ + FROSIX_DB_ACCOUNT_STATUS_HARD_ERROR = -2, + + /** + * Account is valid, but we have no policy stored yet. + */ + FROSIX_DB_ACCOUNT_STATUS_NO_RESULTS = 0, + + /** + * Account is valid, and we have a policy stored. + */ + FROSIX_DB_ACCOUNT_STATUS_VALID_HASH_RETURNED = 1, +}; + + +/** + * Return values for storing data in database with payment. + */ +enum FROSIX_DB_StoreStatus +{ + /** + * The client has stored too many policies, should pay to store more. + */ + FROSIX_DB_STORE_STATUS_STORE_LIMIT_EXCEEDED = -4, + + /** + * The client needs to pay to store policies. + */ + FROSIX_DB_STORE_STATUS_PAYMENT_REQUIRED = -3, + + /** + * Encountered hard error talking to DB. + */ + FROSIX_DB_STORE_STATUS_HARD_ERROR = -2, + + /** + * Despite retrying, we encountered serialization errors. + */ + FROSIX_DB_STORE_STATUS_SOFT_ERROR = -1, + + /** + * Database did not need an update (document exists). + */ + FROSIX_DB_STORE_STATUS_NO_RESULTS = 0, + + /** + * We successfully stored the document. + */ + FROSIX_DB_STORE_STATUS_SUCCESS = 1, +}; + + +/** + * Function called on all pending payments for an account or challenge. + * + * @param cls closure + * @param timestamp for how long have we been waiting + * @param payment_secret payment secret / order id in the backend + * @param amount how much is the order for + */ +typedef void +(*FROSIX_DB_PaymentPendingIterator)( + void *cls, + struct GNUNET_TIME_Timestamp timestamp, + const struct FROSIX_PaymentSecretP *payment_secret, + const struct TALER_Amount *amount); + + +/** + * Function called to test if a given wire transfer + * satisfied the authentication requirement of the + * IBAN plugin. + * + * @param cls closure + * @param credit amount that was transferred + * @param wire_subject subject provided in the wire transfer + * @return true if this wire transfer satisfied the authentication check + */ +typedef bool +(*FROSIX_DB_AuthIbanTransfercheck)( + void *cls, + const struct TALER_Amount *credit, + const char *wire_subject); + + +/** + * Function called on matching meta data. Note that if the client did + * not provide meta data for @a version, the function will be called + * with @a recovery_meta_data being NULL. + * + * @param cls closure + * @param version the version of the recovery document + * @param ts timestamp when the document was uploaded + * @param recovery_meta_data contains meta data about the encrypted recovery document + * @param recovery_meta_data_size size of @a recovery_meta_data blob + * @return #GNUNET_OK to continue to iterate, #GNUNET_NO to abort iteration + */ +typedef enum GNUNET_GenericReturnValue +(*FROSIX_DB_RecoveryMetaCallback)(void *cls, + uint32_t version, + struct GNUNET_TIME_Timestamp ts, + const void *recovery_meta_data, + size_t recovery_meta_data_size); + + +/** + * Handle to interact with the database. + * + * Functions ending with "_TR" run their OWN transaction scope + * and MUST NOT be called from within a transaction setup by the + * caller. Functions ending with "_NT" require the caller to + * setup a transaction scope. Functions without a suffix are + * simple, single SQL queries that MAY be used either way. + */ +struct FROSIX_DatabasePlugin +{ + + /** + * Closure for all callbacks. + */ + void *cls; + + /** + * Name of the library which generated this plugin. Set by the + * plugin loader. + */ + char *library_name; + + /** + * Drop anastasis tables. Used for testcases. + * + * @param cls closure + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ + enum GNUNET_GenericReturnValue + (*drop_tables)(void *cls); + + /** + * Connect to the database. + * + * @param cls closure + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ + enum GNUNET_GenericReturnValue + (*connect)(void *cls); + + /** + * Initialize merchant tables + * + * @param cls closure + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ + enum GNUNET_GenericReturnValue + (*create_tables)(void *cls); + + /** + * Function called to perform "garbage collection" on the + * database, expiring records we no longer require. Deletes + * all user records that are not paid up (and by cascade deletes + * the associated recovery documents). Also deletes expired + * truth and financial records older than @a fin_expire. + * + * @param cls closure + * @param expire_backups backups older than the given time stamp should be garbage collected + * @param expire_pending_payments payments still pending from since before + * this value should be garbage collected + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*gc)(void *cls, + struct GNUNET_TIME_Absolute expire, + struct GNUNET_TIME_Absolute expire_pending_payments); + + /** + * Do a pre-flight check that we are not in an uncommitted transaction. + * If we are, try to commit the previous transaction and output a warning. + * Does not return anything, as we will continue regardless of the outcome. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @return #GNUNET_OK if everything is fine + * #GNUNET_NO if a transaction was rolled back + * #GNUNET_SYSERR on hard errors + */ + enum GNUNET_GenericReturnValue + (*preflight)(void *cls); + + /** + * Check that the database connection is still up. + * + * @param pg connection to check + */ + void + (*check_connection) (void *cls); + + /** + * Roll back the current transaction of a database connection. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @return #GNUNET_OK on success + */ + void + (*rollback) (void *cls); + + /** + * Start a transaction. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param name unique name identifying the transaction (for debugging), + * must point to a constant + * @return #GNUNET_OK on success + */ + int + (*start) (void *cls, + const char *name); + + /** + * Commit the current transaction of a database connection. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @return transaction status code + */ + enum GNUNET_DB_QueryStatus + (*commit)(void *cls); + + + /** + * Register callback to be invoked on events of type @a es. + * + * @param cls database context to use + * @param es specification of the event to listen for + * @param timeout how long to wait for the event + * @param cb function to call when the event happens, possibly + * multiple times (until cancel is invoked) + * @param cb_cls closure for @a cb + * @return handle useful to cancel the listener + */ + struct GNUNET_DB_EventHandler * + (*event_listen)(void *cls, + const struct GNUNET_DB_EventHeaderP *es, + struct GNUNET_TIME_Relative timeout, + GNUNET_DB_EventCallback cb, + void *cb_cls); + + /** + * Stop notifications. + * + * @param eh handle to unregister. + */ + void + (*event_listen_cancel)(struct GNUNET_DB_EventHandler *eh); + + + /** + * Notify all that listen on @a es of an event. + * + * @param cls database context to use + * @param es specification of the event to generate + * @param extra additional event data provided + * @param extra_size number of bytes in @a extra + */ + void + (*event_notify)(void *cls, + const struct GNUNET_DB_EventHeaderP *es, + const void *extra, + size_t extra_size); + + + /** + * FIXME + */ + enum FROSIX_DB_StoreStatus + (*store_dkg_commitment)( + void *cls, + const struct FROSIX_DkgRequestIdP *dkg_id, + const struct FROSIX_DkgCommitmentsRaw *dkg_commits); + + /** + * FIXME + */ + enum GNUNET_DB_QueryStatus + (*get_dkg_commitment)( + void *cls, + const struct FROSIX_DkgRequestIdP *dkg_id, + struct FROSIX_DkgCommitmentsRaw *dkg_commits); + + + /** + * FIXME + */ + enum FROSIX_DB_CommitmentStatus + (*lookup_dkg_commitment)( + void *cls, + const struct FROSIX_DkgRequestIdP *dkg_id); + + + /** + * FIXME + */ + enum FROSIX_DB_StoreStatus + (*store_key)( + void *cls, + const struct FROST_HashCode *id, + const struct FROSIX_EncryptionNonceP *nonce, + const struct FROSIX_KeyDataEncrypted *key_data, + const struct FROSIX_ChallengeHashP *challenge_hash, + uint32_t expiration, + uint8_t identifier); + +/** + * FIXME +*/ + enum FROSIX_DB_KeyStatus + (*lookup_key)( + void *cls, + const struct FROST_HashCode *id); + + + /** + * FIXME + */ + enum GNUNET_DB_QueryStatus + (*get_auth_hash)( + void *cls, + const struct FROST_HashCode *db_id, + struct FROSIX_ChallengeHashP *challenge_hash); + + + /** + * FIXME + */ + enum GNUNET_DB_QueryStatus + (*get_key_data)( + void *cls, + const struct FROST_HashCode *db_id, + uint32_t *identifier, + struct FROSIX_EncryptionNonceP *nonce, + struct FROSIX_KeyDataEncrypted *enc_key_data); + + + /** + * FIXME + */ + enum GNUNET_DB_QueryStatus + (*delete_key_data)( + void *cls, + const struct FROST_HashCode *db_id); + + + /** + * FIXME + */ + enum GNUNET_DB_QueryStatus + (*store_commitment_seed)( + void *cls, + const struct GNUNET_HashCode *db_id, + const struct FROST_CommitmentSeed *seed); + + + /** + * FIXME + */ + enum GNUNET_DB_QueryStatus + (*get_and_delete_commitment_seed)( + void *cls, + const struct GNUNET_HashCode *db_id, + struct FROST_CommitmentSeed *seed); + + + /** + * Verify the provided code with the code on the server. + * If the code matches the function will return with success, if the code + * does not match, the retry counter will be decreased by one. + * + * @param cls closure + * @param truth_uuid identification of the challenge which the code corresponds to + * @param hashed_code code which the user provided and wants to verify + * @param[out] code set to the original numeric code + * @param[out] satisfied set to true if the challenge is set to satisfied + * @return transaction status + */ + enum FROSIX_DB_CodeStatus + (*verify_challenge_code)( + void *cls, + const struct FROSIX_ChallengeIdP *truth_uuid, + const struct GNUNET_HashCode *hashed_code, + uint64_t *code, + bool *satisfied); + + + /** + * Set the 'satisfied' bit for the given challenge and code to + * 'true'. + * + * @param cls closure + * @param truth_uuid identification of the challenge which the code corresponds to + * @param code code which is now satisfied + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*mark_challenge_code_satisfied)( + void *cls, + const struct FROSIX_ChallengeIdP *truth_uuid, + uint64_t code); + + + /** + * Check if the 'satisfied' bit for the given challenge and code is + * 'true' and the challenge code is not yet expired. + * + * @param cls closure + * @param truth_uuid identification of the challenge which the code corresponds to + * @param code code which is now satisfied + * @param after after what time must the challenge have been created + * @return transaction status, + * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the challenge code is not satisfied or expired + * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the challenge code has been marked as satisfied + */ + enum GNUNET_DB_QueryStatus + (*test_challenge_code_satisfied)( + void *cls, + const struct FROSIX_ChallengeIdP *truth_uuid, + const uint64_t code, + struct GNUNET_TIME_Timestamp after); + + + /** + * Insert a new challenge code for a given challenge identified by the challenge + * public key. The function will first check if there is already a valid code + * for this challenge present and won't insert a new one in this case. + * + * @param cls closure + * @param truth_uuid the identifier for the challenge + * @param rotation_period for how long is the code available + * @param validity_period for how long is the code available + * @param retry_counter amount of retries allowed + * @param[out] retransmission_date when to next retransmit + * @param[out] code set to the code which will be checked for later + * @return transaction status, + * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if we are out of valid tries, + * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a code is now in the DB + */ + enum GNUNET_DB_QueryStatus + (*create_challenge_code)( + void *cls, + const struct FROSIX_ChallengeIdP *truth_uuid, + struct GNUNET_TIME_Relative rotation_period, + struct GNUNET_TIME_Relative validity_period, + uint32_t retry_counter, + struct GNUNET_TIME_Timestamp *retransmission_date, + uint64_t *code); + + + /** + * Remember in the database that we successfully sent a challenge. + * + * @param cls closure + * @param truth_uuid the identifier for the challenge + * @param code the challenge that was sent + */ + enum GNUNET_DB_QueryStatus + (*mark_challenge_sent)( + void *cls, + const struct FROSIX_ChallengeIdP *truth_uuid, + uint64_t code); + + + /** + * Store payment for challenge. + * + * @param cls closure + * @param truth_key identifier of the challenge to pay + * @param payment_secret payment secret which the user must provide with every upload + * @param amount how much we asked for + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*record_challenge_payment)( + void *cls, + const struct FROSIX_ChallengeIdP *truth_uuid, + const struct FROSIX_PaymentSecretP *payment_secret, + const struct TALER_Amount *amount); + + + /** + * Record refund for challenge. + * + * @param cls closure + * @param truth_uuid identifier of the challenge to refund + * @param payment_secret payment secret which the user must provide with every upload + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*record_challenge_refund)( + void *cls, + const struct FROSIX_ChallengeIdP *truth_uuid, + const struct FROSIX_PaymentSecretP *payment_secret); + + + /** + * Lookup for a pending payment for a certain challenge + * + * @param cls closure + * @param truth_uuid identification of the challenge + * @param[out] payment_secret set to the challenge payment secret + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*lookup_challenge_payment)( + void *cls, + const struct FROSIX_ChallengeIdP *truth_uuid, + struct FROSIX_PaymentSecretP *payment_secret); + + + /** + * Update payment status of challenge + * + * @param cls closure + * @param truth_uuid which challenge received a payment + * @param payment_identifier proof of payment, must be unique and match pending payment + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*update_challenge_payment)( + void *cls, + const struct FROSIX_ChallengeIdP *truth_uuid, + const struct FROSIX_PaymentSecretP *payment_identifier); + + + /** + * Store inbound IBAN payment made for authentication. + * + * @param cls closure + * @param wire_reference unique identifier inside LibEuFin/Nexus + * @param wire_subject subject of the wire transfer + * @param amount how much was transferred + * @param debit_account account that was debited + * @param credit_account Anastasis operator account credited + * @param execution_date when was the transfer made + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*record_auth_iban_payment)( + void *cls, + uint8_t wire_reference, + const char *wire_subject, + const struct TALER_Amount *amount, + const char *debit_account, + const char *credit_account, + struct GNUNET_TIME_Timestamp execution_date); + + + /** + * Function to check if we are aware of a wire transfer + * that satisfies the IBAN plugin's authentication check. + * + * @param cls closure + * @param debit_account which debit account to check + * @param earliest_date earliest date to check + * @param cb function to call on all entries found + * @param cb_cls closure for @a cb + * @return transaction status, + * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a cb + * returned 'true' once + * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if no + * wire transfers existed for which @a cb returned true + */ + enum GNUNET_DB_QueryStatus + (*test_auth_iban_payment)( + void *cls, + const char *debit_account, + struct GNUNET_TIME_Timestamp earliest_date, + FROSIX_DB_AuthIbanTransfercheck cb, + void *cb_cls); + + + /** + * Function to check the last known IBAN payment. + * + * @param cls closure + * @param credit_account which credit account to check + * @param[out] last_row set to the last known row + * @return transaction status, + * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a cb + * returned 'true' once + * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if no + * wire transfers existed for which @a cb returned true + */ + enum GNUNET_DB_QueryStatus + (*get_last_auth_iban_payment_row)( + void *cls, + const char *credit_account, + uint8_t *last_row); + + + /** + * Function called to remove all expired codes from the database. + * + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*challenge_gc)(void *cls); + + +}; +#endif diff --git a/src/include/frosix_service.h b/src/include/frosix_service.h @@ -0,0 +1,1187 @@ +/* + This file is part of Frosix + Copyright (C) 2019-2022 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + Frosix; see the file COPYING.LIB. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/frosix_service.h + * @brief C interface of libanastasisrest, a C library to use merchant's HTTP API + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + */ +#ifndef FROSIX_SERVICE_H +#define FROSIX_SERVICE_H + +#include "keygen.h" +#include "frosix_util_lib.h" +#include "frosix_crypto.h" +#include <gnunet/gnunet_curl_lib.h> +#include <jansson.h> +#include <taler/taler_util.h> + +#define FROSIX_SEED_SIZE 64 + +/** + * Frosix authorization method configuration + */ +struct FROSIX_AuthorizationMethodConfig +{ + /** + * Type of the method, i.e. "question". + */ + const char *type; + + /** + * Fee charged for accessing key share using this method. + */ + struct TALER_Amount usage_fee; +}; + + +/** + * @brief Frosix configuration data. + */ +struct FROSIX_Config +{ + /** + * FIXME + */ + uint8_t provider_index; + + /** + * Protocol version supported by the server. + */ + const char *version; + + /** + * Business name of the frosix provider. + */ + const char *business_name; + + /** + * Array of authorization methods supported by the server. + */ + const struct FROSIX_AuthorizationMethodConfig *methods; + + /** + * Length of the @e methods array. + */ + unsigned int methods_length; + + /** + * Annual fee for an account / policy upload. + */ + struct TALER_Amount annual_fee; + + /** + * Fee for a truth upload. + */ + struct TALER_Amount signature_creation_fee; + + /** + * Maximum legal liability for data loss covered by the + * provider. + */ + struct TALER_Amount liability_limit; + + /** + * Provider salt. + */ + struct FROSIX_ProviderSaltP provider_salt; + + /** + * Public key of the provider (to verify signatures and encrypt against) + */ + struct GNUNET_CRYPTO_EddsaPublicKey public_key; + +}; + + +/** + * Function called with the result of a /config request. + * Note that an HTTP status of #MHD_HTTP_OK is no guarantee + * that @a fcfg is non-NULL. @a fcfg is non-NULL only if + * the server provided an acceptable response. + * + * @param cls closure + * @param http_status the HTTP status + * @param fcfg configuration obtained, NULL if we could not parse it + */ +typedef void +(*FROSIX_ConfigCallback)(void *cls, + unsigned int http_status, + const struct FROSIX_Config *fcfg); + + +/** + * @brief A Config Operation Handle + */ +struct FROSIX_ConfigOperation +{ + /** + * The url for this request. + */ + char *url; + + /** + * Must not be 0! + */ + uint8_t provider_index; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * Reference to the execution context. + */ + struct GNUNET_CURL_Context *ctx; + + /** + * The callback to pass the backend response to + */ + FROSIX_ConfigCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + +}; + + +/** + * Run a GET /config request against the Frosix backend. + * + * @param ctx CURL context to use + * @param base_url base URL fo the Frosix backend + * @param cb function to call with the results + * @param cb_cls closure for @a cb + * @return handle to cancel the operation + */ +struct FROSIX_ConfigOperation * +FROSIX_get_config (struct GNUNET_CURL_Context *ctx, + const char *base_url, + uint8_t provider_index, + FROSIX_ConfigCallback cb, + void *cb_cls); + + +/** + * Cancel ongoing #FROSIX_get_config() request. + * + * @param co configuration request to cancel. + */ +void +FROSIX_config_cancel (struct FROSIX_ConfigOperation *co); + +/* SEED API */ + +/** + * +*/ +struct FROSIX_Seed +{ + uint8_t bytes[FROSIX_SEED_SIZE]; +}; + + +/** + * +*/ +struct FROSIX_ProviderSeed +{ + /** + * + */ + uint8_t provider_index; + + /** + * + */ + const struct FROSIX_Seed *seed; +}; + +/** + * +*/ +typedef void +(*FROSIX_SeedGetCallback) (void *cls, + unsigned int http_status, + const struct FROSIX_ProviderSeed *ps); + +/** + * @brief A Contract Operation Handle + */ +struct FROSIX_SeedGetOperation +{ + /** + * The url for this request, including parameters. + */ + char *url; + + /** + * Must not be 0! + */ + uint8_t provider_index; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * Function to call with the result. + */ + FROSIX_SeedGetCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Reference to the execution context. + */ + struct GNUNET_CURL_Context *ctx; + +}; + + + +/** + * +*/ +struct FROSIX_SeedGetOperation * +FROSIX_seed_get ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + uint8_t provider_index, + FROSIX_SeedGetCallback cb, + void *cb_cls); + +/** + * +*/ +void +FROSIX_seed_get_cancel ( + struct FROSIX_SeedGetOperation *sgo); + + +/* CONFIG API */ +/* FIXME? */ + + +/*** DKG-COMMITMENT API ***/ + +/** + * High level ways how an dkg-commitment request may conclude. +*/ +enum FROSIX_DkgCommitmentStatus +{ + /** + * Commitment was successfully computed and returned. + */ + FROSIX_DCS_SUCCESS = 0, + + /** + * HTTP interaction failed, see HTTP status. + */ + FROSIX_DCS_HTTP_ERROR, + + /** + * We had an HTTP 400 error, see details in response body. + */ + FROSIX_DCS_CLIENT_ERROR, + + /** + * Server had an internal error. + */ + FROSIX_DCS_SERVER_ERROR +}; + + +/** + * +*/ +struct FROSIX_DkgCommitmentRequestDetails +{ + /** + * High level status of the upload operation. Determines @e details. + */ + enum FROSIX_DkgCommitmentStatus dcs; + + /** + * HTTP status code. + */ + unsigned int http_status; + + /** + * Taler error code. + */ + enum TALER_ErrorCode ec; + + /** + * FIXME + */ + uint8_t provider_index; + + /** + * The returned DKG commitment, must be initialized before use! + */ + struct FROST_DkgCommitment dkg_commitment; + + /** + * Public key of the provider + */ + struct GNUNET_CRYPTO_EddsaPublicKey public_key; +}; + + +/** + * Handle for a POST /dkg-commitment operation +*/ +struct FROSIX_DkgCommitmentRequestOperation; + + +/** + * Callback to process a POST /dkg-commitment request + * + * @param cls closure + * @param dcd the response body +*/ +typedef void +(*FROSIX_DkgCommitmentRequestCallback) ( + void *cls, + const struct FROSIX_DkgCommitmentRequestDetails *dcd); + + +/** + * Ask for a DKG commitment, does a POST /dkg-commitment/$UUID + * + * @param ctx the CURL context used to connect to the backend + * @param backend_url backend's base URL, including final "/" + * @param uuid unique identification of the dkg-commitment request + * @param identifier unique identifier of the provider in the group + * @param threshold number of participants needed to create a valid signature + * @param num_of_participants total number of participants in the group + * @param context_string main source of entropy for the provider to create a commitment + * @param challenge_hash salted hash of challenge method and data + * @param providers_public_keys sorted list of public keys of all involved providers. + * @param cb callback function of the request + * @param cb_cls closure for the callback function + * @return handle for the operation +*/ +struct FROSIX_DkgCommitmentRequestOperation * +FROSIX_dkg_commitment_request ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct FROSIX_DkgRequestIdP *uuid, + uint8_t identifier, + uint8_t threshold, + uint8_t num_of_participants, + const struct FROSIX_DkgContextStringP *context_string, + const struct FROSIX_ChallengeHashP *challenge_hash, + const struct GNUNET_CRYPTO_EddsaPublicKey providers_public_keys[], + FROSIX_DkgCommitmentRequestCallback cb, + void *cb_cls); + + +/** + * Cancel a POST /dkg-commitment request + * + * @param dco the dkg-commitment request operation +*/ +void +FROSIX_dkg_commitment_request_cancel ( + struct FROSIX_DkgCommitmentRequestOperation *dco); + + +/*** DKG-SHARE API ***/ + +/** + * High level ways how an dkg-commitment request may conclude. +*/ +enum FROSIX_DkgShareStatus +{ + /** + * Commitment was successfully computed and returned. + */ + FROSIX_DSS_SUCCESS = 0, + + /** + * HTTP interaction failed, see HTTP status. + */ + FROSIX_DSS_HTTP_ERROR, + + /** + * We had an HTTP 400 error, see details in response body. + */ + FROSIX_DSS_CLIENT_ERROR, + + /** + * Server had an internal error. + */ + FROSIX_DSS_SERVER_ERROR +}; + + +/** + * FIXME +*/ +struct FROSIX_DkgSecretShare +{ + /** + * Identifier of the target of this share + */ + uint8_t target; + + /** + * Identifier of the issuer. This information is intended for the target provider + */ + uint8_t issuer; + + /** + * The encrypted secret share + */ + struct FROSIX_EncryptedShareP encrypted_share; + + /** + * An ephemeral public key, which is needed to decrypt the share + */ + struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key; +}; + + +/** + * +*/ +struct FROSIX_DkgShareRequestDetails +{ + /** + * High level status of the upload operation. Determines @e shares. + */ + enum FROSIX_DkgShareStatus dss; + + /** + * HTTP status code. + */ + unsigned int http_status; + + /** + * Taler error code. + */ + enum TALER_ErrorCode ec; + + /** + * Identifier of the provider + */ + uint8_t provider_index; + + /** + * Pointer to an array of secret shares + */ + struct FROSIX_DkgSecretShare *shares; + + /** + * Number of shares we got + */ + size_t shares_len; +}; + +/** + * FIXME +*/ +struct FROSIX_DkgCommitment +{ + /** + * FIXME + */ + struct FROST_DkgCommitment commitment; + + /** + * FIXME + */ + struct GNUNET_CRYPTO_EcdhePublicKey encryption_public_key; +}; + + +/** + * Handle for a POST /dkg-share operation +*/ +struct FROSIX_DkgShareRequestOperation; + + +/** + * Callback to process a POST /dkg-share request + * + * @param cls closure + * @param dsd the response body +*/ +typedef void +(*FROSIX_DkgShareRequestCallback) ( + void *cls, + const struct FROSIX_DkgShareRequestDetails *dcs); + + +/** + * Ask for encrypted shares in a distributed key generation. Does a POST /dkg-share/$UUID + * + * @param ctx the CURL context used to connect to the backend + * @param backend_url backend's base URL, including final "/" + * @param uuid unique identification of the dkg-commitment request + * @param identifier unique identifier of the provider in the group + * @param threshold number of participants needed to create a valid signature + * @param num_of_participants total number of participants in the group + * @param context_string main source of entropy for the provider to create a commitment + * @param challenge_hash salted hash of challenge method and data + * @param dkg_commitments all the commitments we have to send + * @param len length of @a dkg_commitments array + * @param providers_public_keys sorted list of public keys of all involved providers. + * @param cb callback function of the request + * @param cb_cls closure for the callback function + * @return handle for the operation +*/ +struct FROSIX_DkgShareRequestOperation * +FROSIX_dkg_share_request ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct FROSIX_DkgRequestIdP *uuid, + uint8_t identifier, + uint8_t threshold, + uint8_t num_of_participants, + const struct FROSIX_DkgContextStringP *context_string, + const struct FROSIX_ChallengeHashP *challenge_hash, + const struct FROSIX_DkgCommitment dkg_commitments[], + size_t len, + const struct GNUNET_CRYPTO_EddsaPublicKey providers_public_keys[], + FROSIX_DkgShareRequestCallback cb, + void *cb_cls); + + +/** + * Cancel a POST /dkg-share request + * + * @param dso the dkg-share request operation +*/ +void +FROSIX_dkg_share_request_cancel ( + struct FROSIX_DkgShareRequestOperation *dso); + + +/*** DKG-KEY API ***/ + +/** + * High level ways how an dkg-commitment request may conclude. +*/ +enum FROSIX_DkgKeyStatus +{ + /** + * Commitment was successfully computed and returned. + */ + FROSIX_DKS_SUCCESS = 0, + + /** + * HTTP interaction failed, see HTTP status. + */ + FROSIX_DKS_HTTP_ERROR, + + /** + * We had an HTTP 400 error, see details in response body. + */ + FROSIX_DKS_CLIENT_ERROR, + + /** + * Server had an internal error. + */ + FROSIX_DKS_SERVER_ERROR +}; + + +/** + * +*/ +struct FROSIX_DkgKeyStoreDetails +{ + /** + * High level status of the upload operation. Determines @e details. + */ + enum FROSIX_DkgKeyStatus dks; + + /** + * HTTP status code. + */ + unsigned int http_status; + + /** + * Taler error code. + */ + enum TALER_ErrorCode ec; + + /** + * Identifier of the provider + */ + uint8_t provider_index; + + /** + * The returned data + */ + struct + { + /** + * Our final public key + */ + struct FROST_PublicKey public_key; + + /** + * A signature over the public key and the salted hashes of the challenge + */ + struct GNUNET_CRYPTO_EddsaSignature signature; + } details; +}; + + +/** + * A share for a request to /dkg-key +*/ +struct FROSIX_DkgKeyStoreShare +{ + /** + * Identifier of the issuer of the share + */ + uint8_t identifier; + + /** + * Encrypted secret share + */ + struct FROSIX_EncryptedShareP secret_share; + + /** + * Ephemeral public key to derive the encryption key + */ + struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key; +}; + + +/** + * Handle for a POST /dkg-key operation +*/ +struct FROSIX_DkgKeyStoreOperation; + + +/** + * Callback to process a POST /dkg-key request + * + * @param cls closure + * @param dkd the response body +*/ +typedef void +(*FROSIX_DkgKeyStoreCallback) ( + void *cls, + const struct FROSIX_DkgKeyStoreDetails *dks); + + +/** + * Ask to generate and store key material in a distributed key generation. Does a POST /dkg-key/$UUID + * + * @param ctx the CURL context used to connect to the backend + * @param backend_url backend's base URL, including final "/" + * @param uuid unique identification of the dkg-commitment request + * @param identifier unique identifier of the provider in the group + * @param threshold number of participants needed to create a valid signature + * @param num_of_participants total number of participants in the group + * @param context_string main source of entropy for the provider to create a commitment + * @param challenge_hash salted hash of challenge method and data + * @param providers_public_keys sorted list of public keys of all involved providers. + * @param pre_encryption_key the master key to derive the encryption key, used for the data at the provider + * @param expiration how many years the provider should store the key data + * @param secret_shares array of secret shares + * @param len length of @a dkg_commitments and @a provider_public_keys array + * @param cb callback function of the request + * @param cb_cls closure for the callback function + * @return handle for the operation +*/ +struct FROSIX_DkgKeyStoreOperation * +FROSIX_dkg_key_store ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct FROSIX_DkgRequestIdP *uuid, + uint8_t identifier, + uint8_t threshold, + uint8_t num_of_participants, + const struct FROSIX_DkgContextStringP *context_string, + const struct FROSIX_ChallengeHashP *challenge_hash, + const struct GNUNET_CRYPTO_EddsaPublicKey providers_public_keys[], + const struct FROSIX_EncryptionKey *pre_encryption_key, + unsigned int expiration, + const struct FROSIX_DkgKeyStoreShare secret_shares[], + size_t len, + FROSIX_DkgKeyStoreCallback cb, + void *cb_cls); + + +/** + * Cancel a POST /dkg-key request + * + * @param dso the dkg-key request operation +*/ +void +FROSIX_dkg_key_store_cancel ( + struct FROSIX_DkgKeyStoreOperation *dko); + + +/*** AUTH-CHALLENGE API ***/ + +/** + * High level ways how an sig-commitment request may conclude. +*/ +enum FROSIX_ChallengeRequestStatus +{ + /** + * Commitment was successfully computed and returned. + */ + FROSIX_CRS_SUCCESS = 0, + + /** + * HTTP interaction failed, see HTTP status. + */ + FROSIX_CRS_HTTP_ERROR, + + /** + * We had an HTTP 400 error, see details in response body. + */ + FROSIX_CRS_CLIENT_ERROR, + + /** + * Server had an internal error. + */ + FROSIX_CRS_SERVER_ERROR +}; + + +/** + * +*/ +struct FROSIX_ChallengeRequestDetails +{ + /** + * High level status of the upload operation. Determines @e details. + */ + enum FROSIX_ChallengeRequestStatus crs; + + /** + * HTTP status code. + */ + unsigned int http_status; + + /** + * Taler error code. + */ + enum TALER_ErrorCode ec; + + /** + * Response as JSON + */ + json_t *response; +}; + + +/** + * Handle for a POST /auth-challenge operation +*/ +struct FROSIX_ChallengeRequestOperation; + + +/** + * Callback to process a POST /auth-challenge request + * + * @param cls closure + * @param acd the response body +*/ +typedef void +(*FROSIX_ChallengeRequestCallback) ( + void *cls, + const struct FROSIX_ChallengeRequestDetails *acd); + + +/** + * FIXME +*/ +struct FROSIX_ChallengeRequestOperation * +FROSIX_auth_challenge_post ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct FROSIX_ChallengeRequestIdP *uuid, + const struct FROSIX_EncryptionKey *encryption_key, + const char *auth_method, + const char *auth_data, + const struct GNUNET_HashCode *auth_nonce, + const struct FROST_MessageHash *message_hash, + FROSIX_ChallengeRequestCallback cb, + void *cb_cls); + +/** + * Cancel a POST /auth-challenge request + * + * @param aco the auth-challenge request operation +*/ +void +FROSIX_challenge_request_cancel ( + struct FROSIX_ChallengeRequestOperation *aco); + + +/*** SIG-COMMITMENT API ***/ + +/** + * High level ways how an sig-commitment request may conclude. +*/ +enum FROSIX_SigCommitmentStatus +{ + /** + * Commitment was successfully computed and returned. + */ + FROSIX_SCS_SUCCESS = 0, + + /** + * HTTP interaction failed, see HTTP status. + */ + FROSIX_SCS_HTTP_ERROR, + + /** + * We had an HTTP 400 error, see details in response body. + */ + FROSIX_SCS_CLIENT_ERROR, + + /** + * Server had an internal error. + */ + FROSIX_SCS_SERVER_ERROR +}; + + +/** + * +*/ +struct FROSIX_SigCommitmentRequestDetails +{ + /** + * High level status of the upload operation. Determines @e details. + */ + enum FROSIX_SigCommitmentStatus scs; + + /** + * HTTP status code. + */ + unsigned int http_status; + + /** + * Taler error code. + */ + enum TALER_ErrorCode ec; + + /** + * Position of our provider in the array of providers. + */ + uint8_t array_index; + + /** + * The returned data, a commitment for all other participants + */ + struct FROST_Commitment sig_commitment; +}; + + +/** + * Handle for a POST /sig-commitment operation +*/ +struct FROSIX_SigCommitmentRequestOperation; + + +/** + * Callback to process a POST /sig-commitment request + * + * @param cls closure + * @param scd the response body +*/ +typedef void +(*FROSIX_SigCommitmentRequestCallback) ( + void *cls, + const struct FROSIX_SigCommitmentRequestDetails *scd); + + +/** + * Ask for a commitment to sign a message. Does a POST /sig-commitment/$UUID + * + * @param ctx the CURL context used to connect to the backend + * @param backend_url backend's base URL, including final "/" + * @param uuid unique identification of the dkg-commitment request + * @param identifier identifier of the provider + * @param encryption_key key to decrypt the data stored at the provider + * @param auth_method + * @param auth_data + * @param auth_nonce salt used to hash challenge data + * @param message_hash our data we want to sign + * @param cb callback function of the request + * @param cb_cls closure for the callback function + * @return handle for the operation +*/ +struct FROSIX_SigCommitmentRequestOperation * +FROSIX_sig_commitment_request ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct FROSIX_SigRequestIdP *uuid, + uint8_t identifier, + uint8_t index_in_array, + const struct FROST_HashCode *encryption_key_hash, + const struct GNUNET_HashCode *auth_data, + const struct GNUNET_CRYPTO_Edx25519PublicKey *auth_pub, + const struct GNUNET_CRYPTO_Edx25519Signature *auth_sig, + const char *auth_method, + const struct FROST_MessageHash *message_hash, + FROSIX_SigCommitmentRequestCallback cb, + void *cb_cls); + + +/** + * Cancel a POST /sig-commitment request + * + * @param sco the sig-commitment request operation +*/ +void +FROSIX_sig_commitment_request_cancel ( + struct FROSIX_SigCommitmentRequestOperation *sco); + + + +/*** SIG-SHARE API ***/ + +/** + * High level ways how an sig-share request may conclude. +*/ +enum FROSIX_SigShareStatus +{ + /** + * Signature share was successfully computed and returned. + */ + FROSIX_SSS_SUCCESS = 0, + + /** + * HTTP interaction failed, see HTTP status. + */ + FROSIX_SSS_HTTP_ERROR, + + /** + * We had an HTTP 400 error, see details in response body. + */ + FROSIX_SSS_CLIENT_ERROR, + + /** + * Server had an internal error. + */ + FROSIX_SSS_SERVER_ERROR +}; + + +/** + * +*/ +struct FROSIX_SigShareRequestDetails +{ + /** + * High level status of the upload operation. Determines @e details. + */ + enum FROSIX_SigShareStatus sss; + + /** + * HTTP status code. + */ + unsigned int http_status; + + /** + * Taler error code. + */ + enum TALER_ErrorCode ec; + + /** + * Position in the array. + */ + uint8_t array_index; + + /** + * The returned data, a share of the final signature + */ + struct FROST_SignatureShare sig_share; +}; + + +/** + * Handle for a POST /sig-share operation +*/ +struct FROSIX_SigShareRequestOperation; + + +/** + * Callback to process a POST /sig-share request + * + * @param cls closure + * @param ssd the response body +*/ +typedef void +(*FROSIX_SigShareRequestCallback) ( + void *cls, + const struct FROSIX_SigShareRequestDetails *ssd); + + +/** + * Ask for a share of a signature. Does a POST /sig-share/$UUID + * + * @param ctx the CURL context used to connect to the backend + * @param backend_url backend's base URL, including final "/" + * @param uuid unique identification of the dkg-commitment request + * @param identifier identifier of the provider + * @param encryption_key key to decrypt the data stored at the provider + * @param challenge_solution solution of the authentication challenge + * @param message_hash our data we want to sign + * @param commitments a sorted list of commitments of all participants + * @param len how many commitments do we have? (should be equal to the threshold value) + * @param cb callback function of the request + * @param cb_cls closure for the callback function + * @return handle for the operation +*/ +struct FROSIX_SigShareRequestOperation * +FROSIX_sig_share_request ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct FROSIX_SigRequestIdP *uuid, + uint8_t provider_index, + uint8_t array_index, + const struct FROSIX_EncryptionKey *encryption_key, + const struct FROST_MessageHash *message_hash, + const struct FROST_Commitment commitments[], + size_t len, + FROSIX_SigShareRequestCallback cb, + void *cb_cls); + + +/** + * Cancel a POST /sig-share request + * + * @param sso the sig-share request operation +*/ +void +FROSIX_sig_share_request_cancel ( + struct FROSIX_SigShareRequestOperation *sso); + + +/*** DELETE DKG-KEY API ***/ + +/** + * High level ways how an dkg-key delete request may conclude. +*/ +enum FROSIX_KeyDeleteStatus +{ + /** + * Commitment was successfully computed and returned. + */ + FROSIX_KDS_SUCCESS = 0, + + /** + * HTTP interaction failed, see HTTP status. + */ + FROSIX_KDS_HTTP_ERROR, + + /** + * We had an HTTP 400 error, see details in response body. + */ + FROSIX_KDS_CLIENT_ERROR, + + /** + * Server had an internal error. + */ + FROSIX_KDS_SERVER_ERROR +}; + + +/** + * +*/ +struct FROSIX_KeyDeleteDetails +{ + /** + * High level status of the upload operation. Determines @e details. + */ + enum FROSIX_KeyDeleteStatus kds; + + /** + * HTTP status code. + */ + unsigned int http_status; + + /** + * Taler error code. + */ + enum TALER_ErrorCode ec; +}; + + +/** + * Handle for a DELETE /dkg-key operation +*/ +struct FROSIX_KeyDeleteOperation; + + +/** + * Callback to process a DELETE /dkg-key request + * + * @param cls closure + * @param kdd the response body +*/ +typedef void +(*FROSIX_KeyDeleteCallback) ( + void *cls, + const struct FROSIX_KeyDeleteDetails *kdd); + + +/** + * Ask to generate and store key material in a distributed key generation. Does a POST /dkg-key/$UUID + * + * @param ctx the CURL context used to connect to the backend + * @param backend_url backend's base URL, including final "/" + * @param uuid unique identification of the dkg-key request + * @param cb callback function of the request + * @param cb_cls closure for the callback function + * @return handle for the operation +*/ +struct FROSIX_KeyDeleteOperation * +FROSIX_key_delete ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct FROSIX_DkgRequestIdP *uuid, + FROSIX_KeyDeleteCallback cb, + void *cb_cls); + + +/** + * Cancel a DELETE /dkg-key request + * + * @param kdo the dkg-key request operation +*/ +void +FROSIX_key_delete_cancel ( + struct FROSIX_KeyDeleteOperation *kdo); + + + +#endif diff --git a/src/include/frosix_util_lib.h b/src/include/frosix_util_lib.h @@ -0,0 +1,95 @@ +/* + This file is part of Frosix + Copyright (C) 2020 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/frosix_util_lib.h + * @brief frosix client api + * @author Christian Grothoff + * @author Dominik Meister + * @author Dennis Neufeld + */ +#ifndef FROSIX_UTIL_LIB_H +#define FROSIX_UTIL_LIB_H + +// FIXME +// #include "frosix_error_codes.h" +// #define GNU_TALER_ERROR_CODES_H 1 +#include "frost_low.h" +#include <gnunet/gnunet_util_lib.h> +#include <taler/taler_util.h> + + +/** + * Maximum value allowed for PINs. Limited to 10^15 < 2^52 to ensure the + * numeric value survives a conversion to float by JavaScript. + * + * NOTE: Do not change this value, we map it to a string like + * 42353-256-6521-241 and that mapping fails if the number + * does not have exactly 15 digits! + */ +#define FROSIX_PIN_MAX_VALUE 1000000000000000 + + +/** + * Return default project data used by Frosix. + */ +const struct GNUNET_OS_ProjectData * +FROSIX_project_data_default (void); + + +/** + * Initialize libfrosixsutil. + */ +void +FROSIX_OS_init (void); + + +/*** FOR DEBUGGING ***/ +void +FROSIX_debug_print_point (const struct FROST_Point *pt); + +void +FROSIX_debug_print_scalar (const struct FROST_Scalar *scal); + +void +FROSIX_debug_print_crockford32 (const void *data, + size_t length, + const char *title); + + +/*** NOT IN USE AT THE MOMENT ***/ +/** + * Convert input string @a as into @a pin. + * + * @param as input of the form 42355-256-2262-265 + * @param[out] pin set to numeric pin + * @return false if @as is malformed + */ +bool +FROSIX_scan_pin (const char *as, + unsigned long long *pin); + + +/** + * Convert numeric pin to human-readable number for display. + * + * @param pin number to convert + * @return static (!) buffer with the text to show + */ +const char * +FROSIX_pin2s (uint64_t pin); + + +#endif diff --git a/src/include/frost_high.h b/src/include/frost_high.h @@ -0,0 +1,323 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/frost_high.h + * @brief frosix high level api to create a signature share + * @author Joel Urech +*/ +#ifndef FROST_HIGH_H +#define FROST_HIGH_H + +#include "frost_low.h" +#include <gnunet/gnunet_util_lib.h> + +/** + * Representation of the PUBLIC KEY + */ +struct FROST_PublicKey +{ + /** + * Our public key is an element on the elliptic curve. + */ + struct FROST_Point pk; +}; + +/** + * Representation of the KEY MATERIAL every participant needs in order to + * create a partial signature. + * Gets generated in a key generation process. + */ +struct FROST_KeyPair +{ + /** + * Unique identifier of the participant, must be greater than 0 and less + * than 255. + */ + uint8_t identifier; + /** + * The secret key of the participant, a scalar in the range of the elliptic + * curve. + */ + struct FROST_Scalar my_sk; + /** + * Public key matching the secret key above, as an element on the elliptic + * curve. + */ + struct FROST_Point my_pk; + /** + * Public key to identify the group and to verify the final signatures. + */ + struct FROST_PublicKey group_pk; +}; + +/** + * Representation of a HASH over an arbitrary long message. + */ +struct FROST_MessageHash +{ + /** + * The hash of our message. + */ + struct FROST_HashCode hash; +}; + +/** + * Representation of a NONCE generated by each participant in 'Round 1'. + */ +struct FROST_Nonce +{ + /** + * Secret hiding or blinding value, a random scalar in the range of the elliptic + * curve. + */ + struct FROST_Scalar hiding_nonce; + /** + * Secret binding value, a random scalar in the range of the elliptic curve. + */ + struct FROST_Scalar binding_nonce; +}; + +/** + * Representation of a COMMITMENT generated by each participant in 'Round 1'. + */ +struct FROST_Commitment +{ + /** + * ID of the participant issuing the commitment. + */ + uint8_t identifier; + /** + * Public hiding or blinding value, an element on the elliptic curve. + */ + struct FROST_Point hiding_commitment; + /** + * Public binding value, an element on the elliptic curve. + */ + struct FROST_Point binding_commitment; +}; + +/** + * Representation of a PARTIAL SIGNATURE. + */ +struct FROST_SignatureShare +{ + /** + * Not sure if needed... + */ + uint8_t identifier; + /** + * The resulting signature share, a scalar in the range of the elliptic + * curve. + */ + struct FROST_Scalar sig_share; + /** + * The partial public key for convenience only. + * Otherwise the 'SA' has to compute each partial public key to verify the + * partial signature. + */ + struct FROST_Point pk_i; +}; + + +/** + * Representation of a Schnorr SIGNATURE + */ +struct FROST_Signature +{ + /** + * The 'R' value aka group commitment, as an element on the elliptic curve. + */ + struct FROST_Point r; + /** + * The aggregation of all partial signatures, a scalar in the range of the + * elliptic curve. + * This is the 's' value in a EdDSA signature scheme. + */ + struct FROST_Scalar z; +}; + + +/** + * High entropy value to seed the nonce generation function. + * If this value gets reused, an attack on the private key is possible! +*/ +struct FROST_CommitmentSeed +{ + /** + * The seed is instantiated as a random scalar value from the group. + */ + struct FROST_Scalar scal; +}; + +/** + * Initializes the underlying libsodium library.Always call this function + * first, before using libfrost! + * + * @result Returns 0 on success, -1 on failure and 1 if the library had already + * been initialized. +*/ +int +FROST_init (void); + +/** + * @brief Before a user can start a signing process, he has to convert a message, + * an arbitrary amount of data, into a hash value that we can use. + * + * @param[out] message_hash The resulting hash + * @param[in] msg The real message, a pointer to an abritrary long datablock + * @param msg_len Nmber of bytes, the length, of the given datablock + */ +void +FROST_message_to_hash (struct FROST_MessageHash *message_hash, + const void *msg, + size_t msg_len); + + +/** + * Generates a high entropy and unpredictable random value + * in the range of [0..L[. * L is the order of the ristretto255 group. + * Take care if application runs as a VM, can produce same output if + * snapshotted and restored! + * + * @param[out] seed The returning random and therefore unpredictable bytes. +*/ +void +FROST_get_random_seed (struct FROST_CommitmentSeed *seed); + +/** + * @brief The Signature Aggregator 'SA' (normally the user) chooses 't' (t = threshold) random participants + * out of all available participants and asks them to send him a commitment. + * This function generates a secret nonce- and a public commitment value. + * + * @param[out] nonce The resulting secret nonce, which we will use in 'Round 2' + * @param[out] commitment The resulting public commitment, which we send back to the 'SA' + * @param[in] message_hash Hash of the message to sign. Is part of the commitment + * @param[in] seed A high entropy random seed to generate the commitment from. + * DO NOT USE TWICE! + */ +void +FROST_generate_nonce_and_commitment (struct FROST_Nonce *nonce, + struct FROST_Commitment *commitment, + const struct + FROST_MessageHash *message_hash, + const struct FROST_CommitmentSeed *seed); + +/** + * @brief The 'SA' constructs a sorted list out of all commitments and send this commitment list together with the message hash to each chosen participant. + * Every participant has to verify for each of the received commitments if they are actually two valid encoded points on the curve. + * If the validation fails, abort the signature process and return to the 'SA' which of the commitment has failed. + * + * @param[in] commitment A single commitment to validate + * @return GNUNET_OK if everything is ok, otherwise GNUNET_NO. Abort the signing process in case its not 1! + */ +enum GNUNET_GenericReturnValue +FROST_validate_commitment ( + const struct FROST_Commitment *commitment); + + +/** + * @brief If the validation has not failed, compute a signature share for the given message hash. + * + * Secret key share of participant: \f$s_i\f$ + * Nonce of participant: \f$(d_i, e_i)\f$ + * Lagrange coefficient of participant: \f$\lambda_i\f$ + * Compute binding value of each participant: + * \f$p_i = H(i || m || B)\f$ + * Compute group commitment: + * \f$R_i = D_i(E_i)^{p_i}\f$ + * \f$R = \prod R_i\f$ + * Compute challenge: + * \f$c = H(R || pk || m)\f$ + * Compute signature share: + * \f$z_i = d_i + (e_i \cdot p_i)\lambda_is_ic\f$ + * + * @param[out] signature_share The resulting signature share. We have to return this data back to the 'SA' (\f$(z_i,pk_i)\f$) + * @param[in] message_hash Our message we want to sign (\f$m\f$) + * @param[in] commitments List of all commitments, the order of the elements is crucial! (\f$B\f$) + * @param commitments_len Number of commitments, usually corresponds to the number of participants + * @param my_key_pair Our key material, which was generated by a preliminary key generation process + * @param my_nonce Our secret random value, matching our commitment that we sent previously to the 'SA' + * @return #GNUNET_OK + * #GNUNET_NO + */ +enum GNUNET_GenericReturnValue +FROST_sign_message_hash (struct FROST_SignatureShare *signature_share, + const struct FROST_MessageHash *message_hash, + const struct FROST_Commitment commitments[], + size_t commitments_len, + const struct FROST_KeyPair *my_key_pair, + const struct FROST_Nonce *my_nonce); + +/** + * @brief Gives the 'SA' the possibility to verify each received signature share + * against the commitment from round 1. + * + * Compute binding value of each participant: + * \f$p_i = H(i || m || B)\f$ + * Compute group commitment: + * \f$R_i = D_i(E_i)^{p_i}\f$ + * \f$R = \prod R_i\f$ + * Compute challenge: + * \f$c = H(R || pk || m)\f$ + * Lagrange coefficient of participant: \f$\lambda_i\f$ + * Verify signature share: + * \f$g^{z_i} = R_ipk^{c\lambda_i}\f$ ? + * + * @param[in] commitment_i The commitment that the participant 'i' has previously sent (\f$(D_i, E_i)\f$) + * @param[in] signature_share_i The partial signature of the participant 'i' to be verified (\f$z_i\f$) + * @param[in] commitments List of all commitments. The order of the elements is crucial! (\f$B\f$) + * @param commitments_len Number of commitments, usually corresponds to the number of participants + * @param[in] public_key Group public key is needed to compute the group challenge (\f$pk\f$) + * @param[in] message_hash The hashed message (\f$m\f$) + * @return GNUNET_OK or GNUNET_NO. Abort the signing process in case its not GNUNET_OK! + */ +enum GNUNET_GenericReturnValue +FROST_verify_signature_share (const struct FROST_Commitment *commitment_i, + const struct FROST_SignatureShare + *signature_share_i, + const struct FROST_Commitment commitments[], + uint8_t commitments_len, + const struct FROST_PublicKey *public_key, + const struct FROST_MessageHash *message_hash); + +/** + * @brief Aggregates the signature shares from all participants, computes the group commitment aka 'R' value + * and returns the final signature over the given message. + * Sum all singature shares: + * \f$z = \sum z_i\f$ + * Compute binding value of each participant: + * \f$p_i = H(i || m || B)\f$ + * Compute group commitment: + * \f$R_i = D_i(E_i)^{p_i}\f$ + * \f$R = \prod R_i\f$ + * Resulting signature: + * \f$sig = (R, z)\f$ + * + * @param[out] signature The resulting signature of the given message (\f$sig = (R, z)\f$) + * @param[in] commitments List of all commitments. The order of the elements is crucial! (\f$B\f$) + * @param[in] signature_shares List of all partial signatures. The sorting doesn't matter (\f$z_i\f$) + * @param commitments_and_sig_shares_len Should correspond to the number of participants + * @param[in] message_hash The hashed message as an element on the elliptic curve (\f$m\f$) + */ +void +FROST_compose_signature (struct FROST_Signature *signature, + const struct FROST_Commitment commitments[], + const struct FROST_SignatureShare + signature_shares[], + uint8_t commitments_and_sig_shares_len, + const struct FROST_MessageHash *message_hash); + +#endif diff --git a/src/include/frost_low.h b/src/include/frost_low.h @@ -0,0 +1,451 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file frost_low.h + * @brief Wrapper of all used functions from the crypto library libsodium + * @author Joel Urech +*/ +#ifndef FROST_LOW_H +#define FROST_LOW_H + +#include <sodium.h> + +#define FROST_SCALAR_BYTES crypto_core_ristretto255_SCALARBYTES +#define FROST_POINT_BYTES crypto_core_ristretto255_BYTES + +/** + * FROST_Point represents a 'Ristretto' point on Curve25519 +*/ +struct FROST_Point +{ + /** + * We only have to save the x-coord of our point in ristretto255-encoding + */ + unsigned char xcoord[crypto_core_ristretto255_BYTES]; +}; + +/** + * FROST_Scalar represents a scalar in the range of [0..L[, + * where L is the order of the ristretto255 group +*/ +struct FROST_Scalar +{ + /** + * The scalar bytes + */ + unsigned char scalarbytes[crypto_core_ristretto255_SCALARBYTES]; +}; + +/** + * Representation of a SHA-512 hash +*/ +struct FROST_HashCode +{ + /** + * 64 bytes + */ + unsigned char hashbytes[crypto_hash_sha512_BYTES]; +}; + +/** + * To construct a hash over more than one input, we need a hash state +*/ +struct FROST_HashState +{ + /** + * The internal hash state of libsodium + */ + crypto_hash_sha512_state state; +}; + +/** + * Representation of a SHA-256 hash +*/ +struct FROST_ShortHashCode +{ + /** + * 32 bytes + */ + unsigned char hashbytes[crypto_hash_sha256_BYTES]; +}; + +/** + * To construct a hash over more than one input, we need a hash state +*/ +struct FROST_ShortHashState +{ + /** + * The internal hash state of libsodium + */ + crypto_hash_sha256_state state; +}; + +/** + * Salt to use in computationally intense hashing of a password. +*/ +struct FROST_PowSalt +{ + /** + * 16 bytes + */ + unsigned char bytes[crypto_pwhash_SALTBYTES]; +}; + + +/** + * @brief Initializes the underlying libsodium library. + * + * @result Returns 0 on success, -1 on failure and 1 if the library had already been initialized +*/ +int +FROST_low_init (void); + +// Points +/** + * @brief Multiplies a point with a scalar + * + * @param[out] result The resulting point + * @param[in] pt Input point + * @param[in] scal Input scalar +*/ +void +FROST_point_mul_scalar (struct FROST_Point *result, + const struct FROST_Point *pt, + const struct FROST_Scalar *scal); + +/** + * @brief Adds two points together + * + * @param[out] result The resulting point + * @param[in] p First point + * @param[in] q Second point +*/ +void +FROST_point_add_point (struct FROST_Point *result, + const struct FROST_Point *p, + const struct FROST_Point *q); + +/** + * @brief Substracts point p from point q + * + * @param[out] result The resulting point + * @param[in] p Point which will be subtracted + * @param[in] q Point to subtract of +*/ +void +FROST_point_sub_point (struct FROST_Point *result, + const struct FROST_Point *p, + const struct FROST_Point *q); + +/** + * @brief Provides the identity element + * + * @param[out] result The identity element +*/ +void +FROST_point_identity (struct FROST_Point *result); + +// Scalars +/** + * @brief Multiplies the basepoint with a scalar + * + * @param[out] result The resulting point + * @param[in] scal Input scalar +*/ +void +FROST_base_mul_scalar (struct FROST_Point *result, + const struct FROST_Scalar *scal); + +/** + * @brief Adds two scalars together + * + * @param[out] result The resulting scalar + * @param[in] xscal First scalar + * @param[in] yscal Second scalar +*/ +void +FROST_scalar_add_scalar (struct FROST_Scalar *result, + const struct FROST_Scalar *xscal, + const struct FROST_Scalar *yscal); + +/** + * @brief Multiplies two scalars + * + * @param[out] result The resulting scalar + * @param[in] xscal First scalar + * @param[in] yscal Second scalar +*/ +void +FROST_scalar_mul_scalar (struct FROST_Scalar *result, + const struct FROST_Scalar *xscal, + const struct FROST_Scalar *yscal); + +/** + * @brief Subtracts yscal from xscal + * + * @param[out] result The resulting scalar + * @param[in] xscal Scalar to substract from + * @param[in] yscal Scalar which will be substracted +*/ +void +FROST_scalar_sub_scalar (struct FROST_Scalar *result, + const struct FROST_Scalar *xscal, + const struct FROST_Scalar *yscal); + +/** + * @brief Returns the multiplicative inverse of scal + * + * @param[out] result The resulting scalar + * @param[in] scal Input scalar +*/ +void +FROST_scalar_invert (struct FROST_Scalar *result, + const struct FROST_Scalar *scal); + +// Randomnes +/** + * @brief Provides a random point on Curve25519. + * + * @param[out] result The resulting random point +*/ +void +FROST_point_random (struct FROST_Point *result); + +/** + * @brief Provides a random scalar in the range of [0..L[. + * L is the order of the ristretto255 group + * + * @param[out] result The resulting random scalar +*/ +void +FROST_scalar_random (struct FROST_Scalar *result); + +// Hash functions +/** + * @brief Initializes a hash state (needed for more than one input) + * + * @param[out] state The state which has to be initialized +*/ +void +FROST_hash_init (struct FROST_HashState *state); + +/** + * @brief Allows to hash a byte array of arbitrary length + * + * @param[in,out] state An already initialized hash state has to be provided + * @param[in] msg Pointer to the beginning of the byte array to hash (updates the hash state) + * @param len Length of the byte array to hash +*/ +void +FROST_hash_fixed_update (struct FROST_HashState *state, + const void *msg, + size_t len); + +/** + * @brief Allows to hash a ristretto255 point + * + * @param[in,out] state An already initialized hash state has to be provided + * @param[in] pt The point to hash (updates the hash state) +*/ +void +FROST_hash_point_update (struct FROST_HashState *state, + const struct FROST_Point *pt); + +/** + * @brief Allows to hash a hash in form of the struct FROST_HashCode + * + * @param[in,out] state An already initialized hash state has to be provided + * @param[in] hash The hash to hash (updates the hash state) +*/ +void +FROST_hash_hash_update (struct FROST_HashState *state, + const struct FROST_HashCode *hash); + +/** + * @brief Allows to hash a scalar + * + * @param[in,out] state An already initialized hash state has to be provided + * @param[in] scal The scalar to hash (updates the hash state) +*/ +void +FROST_hash_scalar_update (struct FROST_HashState *state, + const struct FROST_Scalar *scal); + +/** + * @brief Allows to hash an uint8 value + * + * @param[in,out] state An already initialized hash state has to be provided + * @param identifier The uint8 value to hash (updates the hash state) +*/ +void +FROST_hash_uint8_update (struct FROST_HashState *state, + const uint8_t identifier); + +/** + * @brief Transforms an updated hash state to a final hash value + * + * @param[in] state An already initialized and with at least one value updated hash state has to be provided + * @param[out] result The resulting hash value (SHA512) +*/ +void +FROST_hash_final (struct FROST_HashState *state, + struct FROST_HashCode *result); + +/** + * @brief Maps a hash value to a point on the curve + * + * @param[out] result The resulting point + * @param[in] hash Hash input +*/ +void +FROST_hash_to_curve (struct FROST_Point *result, + const struct FROST_HashCode *hash); + +/** + * @brief Reduces a hash value to a scalar in the range of the order of the ristretto255 group + * + * @param[out] result The resulting scalar + * @param[in] hash Hash input +*/ +void +FROST_hash_to_scalar (struct FROST_Scalar *result, + const struct FROST_HashCode *hash); + +/** + * FIXME +*/ +enum GNUNET_GenericReturnValue +FROST_hash_cmp (const struct FROST_HashCode *first, + const struct FROST_HashCode *second); + +/** + * FIXME +*/ +void +FROST_short_hash_init (struct FROST_ShortHashState *state); + +/** + * +*/ +void +FROST_short_hash_update_fixed (struct FROST_ShortHashState *state, + const void *msg, + size_t len); + +/** + * FIXME +*/ +void +FROST_short_hash_final (struct FROST_ShortHashState *state, + struct FROST_ShortHashCode *result); + + +// Helper functions +/** + * @brief Copies the value of a point + * + * @param[out] destination Point to copy to + * @param[in] origin Point to copy from +*/ +void +FROST_point_copy_to (struct FROST_Point *destination, + const struct FROST_Point *origin); + +/** + * @brief Copies the value of a scalar + * + * @param[out] destination Scalar to copy to + * @param[in] origin Scalar to copy from +*/ +void +FROST_scalar_copy_to (struct FROST_Scalar *destination, + const struct FROST_Scalar *origin); + +/** + * @brief Sets a FROST_Scalar to 0 + * + * @param[out] scal The scalar to set to 0 +*/ +void +FROST_scalar_zero (struct FROST_Scalar *scal); + +/** + * @brief Sets a FROST_Scalar to 1 + * + * @param[out] scal The scalar to set to 1 +*/ +void +FROST_scalar_one (struct FROST_Scalar *scal); + +/** + * @brief Sets a FROST_Scalar to a value of an uint8 + * + * @param[out] result The resulting scalar + * @param number Uint8 value +*/ +void +FROST_scalar_set_uint8 (struct FROST_Scalar *result, + uint8_t number); + +/** + * @brief Compares two point on equality + * + * @param[in] p First point to compare + * @param[in] q Second point to compare + * @return GNUNET_OK if both points are equal, GNUNET_NO otherwise +*/ +enum GNUNET_GenericReturnValue +FROST_point_cmp (const struct FROST_Point *p, + const struct FROST_Point *q); + +/** + * @brief Provides a check if the given point is a valid ristretto255-encoded element + * + * @param[in] p Point to validate + * @return GNUNET_OK or GNUNET_NO +*/ +enum GNUNET_GenericReturnValue +FROST_is_valid_point (const struct FROST_Point *p); + + +/** + * Takes a single high entropy key and derives a scalar, mapped to the curve + * from it. + * + * + * @param[out] subkey The resulting derived key, mapped as a scalar to the curve. + * @param[in] subkey_id Submit a different @a subkey_id to derive a different + * subkey. + * @param[in] masterkey Source of entropy to derive the @a subkey from. Make + * sure to provide 32 bytes of high entropy! +*/ +void +FROST_kdf_scalar_to_curve (struct FROST_Scalar *subkey, + uint64_t subkey_id, + const struct FROST_ShortHashCode *masterkey); + + +/** + * FIXME +*/ +enum GNUNET_GenericReturnValue +FROST_pow_hash (struct FROST_HashCode *hash, + const char *answer, + size_t length, + const struct FROST_PowSalt *salt, + uint8_t difficulty); + +#endif diff --git a/src/include/frost_verify.h b/src/include/frost_verify.h @@ -0,0 +1,44 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/frost_verify.h + * @brief frosix api to verify a signature + * @author Joel Urech +*/ +#ifndef FROST_VERIFY_H +#define FROST_VERIFY_H + +#include "frost_high.h" + +/** + * Verifies the validity of a given signature and hash of a message against a public key. + * Since we create signatures which are compatible with the widespread EdDSA signature scheme, + * this verification function does the same as every implementation of a EdDSA compatible verificiation function: + * \f$sig = (r, z)\f$ + * \f$c = H(r || pk || m)\f$ + * \f$r = g^z - pk^c\f$ ? + * + * @param[in] public_key The corresponding public key + * @param[in] signature The signature to verify + * @param[in] message_hash Hash of the message, which has been signed, as an element on the elliptic curve + * @return GNUNET_OK if signature is valid, otherwise GNUNET_NO + */ +enum GNUNET_GenericReturnValue +FROST_verify_signature (const struct FROST_PublicKey *public_key, + const struct FROST_Signature *signature, + const struct FROST_MessageHash *message_hash); + +#endif diff --git a/src/include/gettext.h b/src/include/gettext.h @@ -0,0 +1,311 @@ +/* Convenience header for conditional use of GNU <libintl.h>. + Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2020 Free Software + Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option + or through "#define ENABLE NLS 0" before including this file. */ +#if defined ENABLE_NLS && ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +# include <libintl.h> + +/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by + the gettext() and ngettext() macros. This is an alternative to calling + textdomain(), and is useful for libraries. */ +# ifdef DEFAULT_TEXT_DOMAIN +# undef gettext +# define gettext(Msgid) \ + dgettext (DEFAULT_TEXT_DOMAIN, Msgid) +# undef ngettext +# define ngettext(Msgid1, Msgid2, N) \ + dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) +# endif + +#else + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of <locale.h> a NOP. We don't include <libintl.h> + as well because people using "gettext.h" will not include <libintl.h>, + and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> + is OK. */ +#if defined(__sun) +# include <locale.h> +#endif + +/* Many header files from the libstdc++ coming with g++ 3.3 or newer include + <libintl.h>, which chokes if dcgettext is defined as a macro. So include + it now, to make later inclusions of <libintl.h> a NOP. */ +#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) +# include <cstdlib> +# if (__GLIBC__ >= 2 && ! defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H +# include <libintl.h> +# endif +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +# undef gettext +# define gettext(Msgid) ((const char *) (Msgid)) +# undef dgettext +# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) +# undef dcgettext +# define dcgettext(Domainname, Msgid, Category) \ + ((void) (Category), dgettext (Domainname, Msgid)) +# undef ngettext +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 \ + ? ((void) (Msgid2), (const char *) (Msgid1)) \ + : ((void) (Msgid1), (const char *) (Msgid2))) +# undef dngettext +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((void) (Domainname), ngettext (Msgid1, Msgid2, N)) +# undef dcngettext +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((void) (Category), dngettext (Domainname, Msgid1, Msgid2, N)) +# undef textdomain +# define textdomain(Domainname) ((const char *) (Domainname)) +# undef bindtextdomain +# define bindtextdomain(Domainname, Dirname) \ + ((void) (Domainname), (const char *) (Dirname)) +# undef bind_textdomain_codeset +# define bind_textdomain_codeset(Domainname, Codeset) \ + ((void) (Domainname), (const char *) (Codeset)) + +#endif + +/* Prefer gnulib's setlocale override over libintl's setlocale override. */ +#ifdef GNULIB_defined_setlocale +# undef setlocale +# define setlocale rpl_setlocale +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +/* The separator between msgctxt and msgid in a .mo file. */ +#define GETTEXT_CONTEXT_GLUE "\004" + +/* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a + MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be + short and rarely need to change. + The letter 'p' stands for 'particular' or 'special'. */ +#ifdef DEFAULT_TEXT_DOMAIN +# define pgettext(Msgctxt, Msgid) \ + pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \ + LC_MESSAGES) +#else +# define pgettext(Msgctxt, Msgid) \ + pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) +#endif +#define dpgettext(Domainname, Msgctxt, Msgid) \ + pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \ + LC_MESSAGES) +#define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ + pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category) +#ifdef DEFAULT_TEXT_DOMAIN +# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ + npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \ + MsgidPlural, N, LC_MESSAGES) +#else +# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ + npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, \ + N, LC_MESSAGES) +#endif +#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ + npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \ + MsgidPlural, N, LC_MESSAGES) +#define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ + npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \ + MsgidPlural, N, Category) + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +pgettext_aux (const char *domain, + const char *msg_ctxt_id, const char *msgid, + int category) +{ + const char *translation = dcgettext (domain, msg_ctxt_id, category); + if (translation == msg_ctxt_id) + return msgid; + else + return translation; +} + + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +npgettext_aux (const char *domain, + const char *msg_ctxt_id, const char *msgid, + const char *msgid_plural, unsigned long int n, + int category) +{ + const char *translation = + dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); + if ((translation == msg_ctxt_id) || (translation == msgid_plural)) + return (n == 1 ? msgid : msgid_plural); + else + return translation; +} + + +/* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID + can be arbitrary expressions. But for string literals these macros are + less efficient than those above. */ + +#include <string.h> + +/* GNULIB_NO_VLA can be defined to disable use of VLAs even if supported. + This relates to the -Wvla and -Wvla-larger-than warnings, enabled in + the default GCC many warnings set. This allows programs to disable use + of VLAs, which may be unintended, or may be awkward to support portably, + or may have security implications due to non-deterministic stack usage. */ + +#if (! defined GNULIB_NO_VLA \ + && (((__GNUC__ >= 3 || __GNUG__ >= 2) && ! defined __STRICT_ANSI__) \ + /* || (__STDC_VERSION__ == 199901L && !defined __HP_cc) + || (__STDC_VERSION__ >= 201112L && !defined __STDC_NO_VLA__) */)) +# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 1 +#else +# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 0 +#endif + +#if ! _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS +#include <stdlib.h> +#endif + +#define pgettext_expr(Msgctxt, Msgid) \ + dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES) +#define dpgettext_expr(Domainname, Msgctxt, Msgid) \ + dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES) + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +dcpgettext_expr (const char *domain, + const char *msgctxt, const char *msgid, + int category) +{ + size_t msgctxt_len = strlen (msgctxt) + 1; + size_t msgid_len = strlen (msgid) + 1; + const char *translation; +#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + char msg_ctxt_id[msgctxt_len + msgid_len]; +#else + char buf[1024]; + char *msg_ctxt_id = + (msgctxt_len + msgid_len <= sizeof (buf) + ? buf + : (char *) malloc (msgctxt_len + msgid_len)); + if (msg_ctxt_id != NULL) +#endif + { + int found_translation; + memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); + msg_ctxt_id[msgctxt_len - 1] = '\004'; + memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); + translation = dcgettext (domain, msg_ctxt_id, category); + found_translation = (translation != msg_ctxt_id); +#if ! _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + if (msg_ctxt_id != buf) + free (msg_ctxt_id); +#endif + if (found_translation) + return translation; + } + return msgid; +} + + +#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ + dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) +#define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ + dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +dcnpgettext_expr (const char *domain, + const char *msgctxt, const char *msgid, + const char *msgid_plural, unsigned long int n, + int category) +{ + size_t msgctxt_len = strlen (msgctxt) + 1; + size_t msgid_len = strlen (msgid) + 1; + const char *translation; +#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + char msg_ctxt_id[msgctxt_len + msgid_len]; +#else + char buf[1024]; + char *msg_ctxt_id = + (msgctxt_len + msgid_len <= sizeof (buf) + ? buf + : (char *) malloc (msgctxt_len + msgid_len)); + if (msg_ctxt_id != NULL) +#endif + { + int found_translation; + memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); + msg_ctxt_id[msgctxt_len - 1] = '\004'; + memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); + translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); + found_translation = ! (translation == msg_ctxt_id || translation == + msgid_plural); +#if ! _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + if (msg_ctxt_id != buf) + free (msg_ctxt_id); +#endif + if (found_translation) + return translation; + } + return (n == 1 ? msgid : msgid_plural); +} + + +#endif /* _LIBGETTEXT_H */ diff --git a/src/include/keygen.h b/src/include/keygen.h @@ -0,0 +1,269 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/keygen.h + * @brief frosix api to create a key pair in a distributed key generation + * process. + * @author Joel Urech +*/ +#ifndef FROST_KEYGEN_H +#define FROST_KEYGEN_H + +#include "frost_high.h" + +/** + * A commitment for a single share in a dkg. +*/ +struct FROST_DkgShareCommitment +{ + /** + * Our commitment is g^'share' + */ + struct FROST_Point sc; +}; + +/** + * A zero knowledge proof of the secret at x-coord 0 in our polynomial. + * In principle it is a Schnorr signature. +*/ +struct FROST_DkgZkp +{ + /** + * The nonce of our zkp. + */ + struct FROST_Point r; + /** + * Proof of knowing the secret value. + */ + struct FROST_Scalar z; +}; + +/** + * In the first round of the distributed key generation process, + * every participant has to send a special commitment to all other. + * This structs contains all needed data for this commitment. +*/ +struct FROST_DkgCommitment +{ + /** + * Unique identifier of the participant, must be greater than 0 and less than 255. + */ + uint8_t identifier; + /** + * A pointer to an array of commitments. + * The number of commitments depends on the choosen threshold value, + * which can vary between 2 and 253. To initialize this struct, + * call FROST_initialize_dkg_commitment(). + */ + struct FROST_DkgShareCommitment *share_comm; + /** + * The length of the commitment array + */ + uint8_t shares_commitments_length; + /** + * A zero knowledge proof of the underlying secret value. + */ + struct FROST_DkgZkp zkp; +}; + +/** + * +*/ + +/** + * Representation of a distributed key generation secret share (not the final key share!). + * This struct will be used in the second and third round of the distributed key generation + * process. +*/ +struct FROST_DkgShare +{ + /** + * Unique identifier of the participant, must be greater than 0 and less than 255 + */ + uint8_t identifier; + /** + * A secret value, which is intended only for a particular participant. + * It has to match one of the commitments from round 1! + */ + struct FROST_Scalar share; +}; + +/** + * FIXME +*/ +struct FROST_DkgContextString +{ + /** + * FIXME + */ + struct FROST_ShortHashCode con_str; +}; + +/** + * Trusted dealer should only be used for testing purposes. + * It creates key material using only local entropy. + * + * @param[out] key_pairs An array with the resulting key material and this + * array contains a key pair for every participant. + * @param[in] num_of_participants In how many parts should the secret key get + * divided? This is also the length of the `key_pairs` array. + * @param[in] threshold How many participants have to participate in the + * signing process? The threshold value also determines one of the big security + * parameters of our system. Do not choose it too low! +*/ +void +FROST_trusted_dealer_keygen (struct FROST_KeyPair key_pairs[], + uint8_t num_of_participants, + uint8_t threshold); + + +/** + * Checks if the provided params are valid. + * + * @param[in] identifier unique identifier of the participant in the group + * @param[in] threshold threshold value to create a valid signature + * @param[in] num_of_participant total number of participant + * @return GNUNET_OK or GNUNET_NO +*/ +enum GNUNET_GenericReturnValue +FROST_validate_dkg_params (uint8_t identifier, + uint8_t threshold, + uint8_t num_of_participants); + +/** + * Call this function always before starting a dkg. + * It will initialize the struct `FROST_DkgCommitment`, which contains an array + * of length `threshold`. + * + * @param[out] dkg_commitment The commitment which should be initialized. + * @param[in] my_index Unique identifier of the participant, must be greater + * than 0 and less than 255. + * @param[in] threshold How many participants have to participate in the + * signing process? The threshold value also fixes the length of the inner + * array. + * @return GNUNET_OK or GNUNET_NO +*/ +enum GNUNET_GenericReturnValue +FROST_initialize_dkg_commitment (struct FROST_DkgCommitment *dkg_commitment, + uint8_t my_index, + uint8_t threshold); + +/** + * Every participant first do a trusted dealer on his own and commits to each + * of the t-1 generated values. + * Additionally, every participant has to compute a zero knowledge proof of + * the underlying secret (y-value of x=0). As a result, this function returns + * a commitment, which should then be send to all other participants. + * Do not send the dkg shares now! + * + * @a context_string should be the hash of the received context_string, + * concatenated with the secret provider salt and other values like the salted + * hash of the authentication method and the salted hash of the authentication + * data. + * + * @param[in,out] dkg_commitment This struct must first be initialized with + * FROST_initialize_dkg_commitment. After calling FROST_keygen_begin, the inner + * array will be filled with a commitment to each of the t-1 share values. + * @param[out] dkg_shares This are the precomputed shares, one share for each + * participant. The length of this array MUST be 'num_of_participants - 1'. + * @param[in] context_string Source of entropy to derive all 'rnd' values. + * @param[in] addtional_data There is the possibility to include additional + * data in form of a hash in the zero knowledge proof. NULL possible. + * @param[in] my_index Unique identifier of the participant, must be greater + * than 0 and less than 255. + * @param[in] num_of_participants How many participants are participating in + * the distributed key generation process? + * @param[in] threshold How many participants have to participate in the + * signing process? + * @return GNUNET_OK or GNUNET_NO +*/ +enum GNUNET_GenericReturnValue +FROST_keygen_begin (struct FROST_DkgCommitment *dkg_commitment, + struct FROST_DkgShare dkg_shares[], + const struct FROST_DkgContextString *context_string, + const struct FROST_HashCode *additional_data, + uint8_t my_index, + uint8_t num_of_participants, + uint8_t threshold); + +/** + * After receiving all commitments from all other participants, they have to be + * validated. This means, that every value will be checked if it is a correctly + * encoded ristretto255 element. Additionally the included zero knowledge proof + * has to be validated too. + * + * @param[in] dkg_commitment A sorted list of all commitments. + * @param[in] num_of_participants How many participants are participating in + * the distributed key generation process? + * @return GNUNET_OK or GNUNET_NO +*/ +enum GNUNET_GenericReturnValue +FROST_keygen_validate_commitment ( + const struct FROST_DkgCommitment *dkg_commitment, + const struct FROST_HashCode *additional_data, + uint8_t num_of_participants); + +/** + * Finally send to each participant his share and receive from each participant + * a share. + * This shares has to be verified against the previously received commitments. + * + * @param[in] commitment The dkg commitment, including all share commitments + * @param[in] share The share we validate with the dkg commitment + * @param[in] my_index What is my identifier number? + * @return GNUNET_OK or GNUNET_NO +*/ +enum GNUNET_GenericReturnValue +FROST_keygen_validate_share ( + const struct FROST_DkgCommitment *commitment, + const struct FROST_DkgShare *share, + uint8_t my_index); + +/** + * With all these shares, this function computes the individual key pair and + * derives the group public key from the commitments. + * + * @param[out] key_pair The resulting key material, keep it safe and secure! + * @param[in] my_index Unique identifier of the participant, must be greater + * than 0 and less than 255. + * @param[in] shares The precomputed shares, received one share from each + * participant. + * @param[in] commitments The previously received and already validated + * commitments. There has to be a corresponding value to each of the received + * shares. + * @param[in] num_of_participants How many participants are participating in + * the distributed key generation process? +*/ +void +FROST_keygen_finalize (struct FROST_KeyPair *key_pair, + uint8_t my_index, + const struct FROST_DkgShare shares[], + const struct FROST_DkgCommitment commitments[], + uint8_t num_of_participants); + +/** + * Counterpart to the initializing function of the struct dkg commitment. + * This function frees allocated space. + * + * @param[in,out] dkg_commitment The struct which was initialized with + * `FROST_initialize_dkg_commitment` at the beginning of the dkg process. + * @param[in] length Number of commitments elements. +*/ +void +FROST_free_dkg_commitment (struct FROST_DkgCommitment dkg_commitments[], + size_t length); + +#endif diff --git a/src/include/platform.h b/src/include/platform.h @@ -0,0 +1,289 @@ +/* + This file is part of Frosix + Copyright (C) 2014, 2015, 2016, 2021 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file include/platform.h + * @brief This file contains the includes and definitions which are used by the + * rest of the modules + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + */ + +#ifndef PLATFORM_H_ +#define PLATFORM_H_ + +/* Include our configuration header */ +#ifndef HAVE_USED_CONFIG_H +#define HAVE_USED_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "frosix_config.h" +#endif +#endif + + +#if (GNUNET_EXTRA_LOGGING >= 1) +#define VERBOSE(cmd) cmd +#else +#define VERBOSE(cmd) do { break; } while (0) +#endif + + +/* LSB-style exit status codes */ +#ifndef EXIT_INVALIDARGUMENT +#define EXIT_INVALIDARGUMENT 2 +#endif + +#ifndef EXIT_NOTIMPLEMENTED +#define EXIT_NOTIMPLEMENTED 3 +#endif + +#ifndef EXIT_NOPERMISSION +#define EXIT_NOPERMISSION 4 +#endif + +#ifndef EXIT_NOTINSTALLED +#define EXIT_NOTINSTALLED 5 +#endif + +#ifndef EXIT_NOTCONFIGURED +#define EXIT_NOTCONFIGURED 6 +#endif + +#ifndef EXIT_NOTRUNNING +#define EXIT_NOTRUNNING 7 +#endif + + +/* Include the features available for GNU source */ +#define _GNU_SOURCE + + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef __clang__ +#undef HAVE_STATIC_ASSERT +#endif + +/** + * These may be expensive, but good for debugging... + */ +#define ALLOW_EXTRA_CHECKS GNUNET_YES + +/** + * For strptime (glibc2 needs this). + */ +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 499 +#endif + +#ifndef _REENTRANT +#define _REENTRANT +#endif + +/* configuration options */ + +#define VERBOSE_STATS 0 + +#include <netdb.h> +#include <sys/socket.h> +#include <sys/un.h> +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if HAVE_NETINET_IN_SYSTM_H +#include <netinet/in_systm.h> +#endif +#if HAVE_NETINET_IP_H +#include <netinet/ip.h> /* superset of previous */ +#endif +#include <arpa/inet.h> +#include <netinet/tcp.h> +#include <pwd.h> +#include <sys/ioctl.h> +#include <sys/wait.h> +#include <grp.h> + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdbool.h> +#include <errno.h> +#include <signal.h> +#include <libgen.h> +#ifdef HAVE_MALLOC_H +#include <malloc.h> /* for mallinfo on GNU */ +#endif +#include <unistd.h> /* KLB_FIX */ +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> /* KLB_FIX */ +#include <fcntl.h> +#include <math.h> +#if HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif +#if HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#include <time.h> +#ifdef BSD +#include <net/if.h> +#endif +#if defined(BSD) && defined(__FreeBSD__) && defined(__FreeBSD_kernel__) +#include <semaphore.h> +#endif +#ifdef DARWIN +#include <dlfcn.h> +#include <semaphore.h> +#include <net/if.h> +#endif +#if defined(__linux__) || defined(GNU) +#include <net/if.h> +#endif +#ifdef SOLARIS +#include <sys/sockio.h> +#include <sys/filio.h> +#include <sys/loadavg.h> +#include <semaphore.h> +#endif +#if HAVE_UCRED_H +#include <ucred.h> +#endif +#if HAVE_SYS_UCRED_H +#include <sys/ucred.h> +#endif +#if HAVE_IFADDRS_H +#include <ifaddrs.h> +#endif +#include <errno.h> +#include <limits.h> + +#if HAVE_VFORK_H +#include <vfork.h> +#endif + +#include <ctype.h> +#if HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif + +#if HAVE_ENDIAN_H +#include <endian.h> +#endif +#if HAVE_SYS_ENDIAN_H +#include <sys/endian.h> +#endif + +#define DIR_SEPARATOR '/' +#define DIR_SEPARATOR_STR "/" +#define PATH_SEPARATOR ':' +#define PATH_SEPARATOR_STR ":" +#define NEWLINE "\n" + +#include <locale.h> +#include "gettext.h" +/** + * GNU gettext support macro. + */ +#define _(String) dgettext (PACKAGE, String) +#define LIBEXTRACTOR_GETTEXT_DOMAIN "libextractor" + +#include <sys/mman.h> + +/* FreeBSD_kernel is not defined on the now discontinued kFreeBSD */ +#if defined(BSD) && defined(__FreeBSD__) && defined(__FreeBSD_kernel__) +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN +#endif + +#ifdef DARWIN +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN +/* not available on darwin, override configure */ +#undef HAVE_STAT64 +#undef HAVE_MREMAP +#endif + +#if ! HAVE_ATOLL +long long +atoll (const char *nptr); + +#endif + +#if ENABLE_NLS +#include "langinfo.h" +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX ((size_t) (-1)) +#endif + +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif + +/** + * AI_NUMERICSERV not defined in windows. Then we just do without. + */ +#ifndef AI_NUMERICSERV +#define AI_NUMERICSERV 0 +#endif + + +#if defined(__sparc__) +#define MAKE_UNALIGNED(val) ({ __typeof__((val)) __tmp; memmove (&__tmp, &(val), \ + sizeof((val))); \ + __tmp; }) +#else +#define MAKE_UNALIGNED(val) val +#endif + +/** + * The termination signal + */ +#define GNUNET_TERM_SIG SIGTERM + + +#ifndef PATH_MAX +/** + * Assumed maximum path length. + */ +#define PATH_MAX 4096 +#endif + +#if HAVE_THREAD_LOCAL_GCC +#define ANASTASIS_THREAD_LOCAL __thread +#else +#define ANASTASIS_THREAD_LOCAL +#endif + + +/* Do not use shortcuts for gcrypt mpi */ +#define GCRYPT_NO_MPI_MACROS 1 + +/* Do not use deprecated functions from gcrypt */ +#define GCRYPT_NO_DEPRECATED 1 + +/* Ignore MHD deprecations for now as we want to be compatible + to "ancient" MHD releases. */ +#define MHD_NO_DEPRECATION 1 + +#endif /* PLATFORM_H_ */ + +/* end of platform.h */ diff --git a/src/libfrosix/Makefile.am b/src/libfrosix/Makefile.am @@ -0,0 +1,32 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/backend + + +lib_LTLIBRARIES = \ + libfrosix.la + +libfrosix_la_LDFLAGS = \ + -version-info 0:0:0 \ + -no-undefined +libfrosix_la_SOURCES = \ + frosix_api_keygen.c \ + frosix_api_sign.c \ + frosix_api_request-challenge.c \ + frosix_api_delete-key.c \ + frosix_api.c frosix_api.h \ +libfrosix_la_LIBADD = \ + $(top_builddir)/src/restclient/libfrosixrest.la \ + $(top_builddir)/src/util/libfrosixutil.la \ + -lgnunetjson \ + -lgnunetcurl \ + -lgnunetutil \ + -ltalermhd \ + -ltalerutil \ + -ltalerexchange \ + -ltalermerchant \ + -ltalerjson \ + -ljansson \ + -lgcrypt \ + -ldl \ + -lm \ + $(XLIB) diff --git a/src/libfrosix/frosix_api.c b/src/libfrosix/frosix_api.c @@ -0,0 +1,319 @@ +/* + This file is part of Frosix + Copyright (C) 2020, 2021, 2022 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file libfrosix/frosix_api.c + * @brief frosix client api + * @author Christian Grothoff + * @author Dominik Meister + * @author Dennis Neufeld + */ +#include <platform.h> +#include <jansson.h> +#include "frosix.h" +// #include "anastasis_error_codes.h" +#include <taler/taler_json_lib.h> +#include "frosix_api.h" +#include "frost_verify.h" +#include "frost_high.h" +#include "frost_low.h" +#include "frost_high.h" + + +/** + * Reducer API's CURL context handle. + */ +struct GNUNET_CURL_Context *FROSIX_REDUX_ctx_; + +void +FROSIX_redux_fail_ (FROSIX_ActionCallback cb, + void *cb_cls, + enum TALER_ErrorCode ec, + const char *detail) +{ + json_t *estate; + + estate = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_string ("detail", + detail)), + GNUNET_JSON_pack_string ("reducer_type", + "error"), + GNUNET_JSON_pack_uint64 ("code", + ec), + GNUNET_JSON_pack_string ("hint", + TALER_ErrorCode_get_hint (ec))); + cb (cb_cls, + ec, + estate); + json_decref (estate); +} + + +void +FROSIX_redux_init (struct GNUNET_CURL_Context *ctx) +{ + FROSIX_REDUX_ctx_ = ctx; +} + + +void +FROSIX_redux_action_cancel (struct FROSIX_ReduxAction *ra) +{ + ra->cleanup (ra->cleanup_cls); +} + + +enum GNUNET_GenericReturnValue +FROSIX_verify_signature (const char *message, + const json_t *arguments) +{ + /* parse json */ + struct FROST_MessageHash mh; + struct FROST_PublicKey pk; + struct FROST_Signature sig; + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("message_hash", + &mh), + GNUNET_JSON_spec_fixed_auto ("public_key", + &pk), + GNUNET_JSON_spec_fixed_auto ("signature_r", + &sig.r), + GNUNET_JSON_spec_fixed_auto ("signature_z", + &sig.z), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != GNUNET_JSON_parse (arguments, + spec, + NULL, + NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + return GNUNET_NO; + } + + /* check if hash of message matches hash in signature */ + struct FROST_MessageHash input_mh; + FROST_message_to_hash (&input_mh, + message, + strlen (message)); + + if (GNUNET_OK != FROST_hash_cmp (&mh.hash, + &input_mh.hash)) + return GNUNET_NO; + + return FROST_verify_signature (&pk, + &sig, + &mh); +} + + +void +FROSIX_export_public_key (const json_t *arguments, + FROSIX_ActionCallback cb, + void *cb_cls) +{ + json_t *result = json_object (); + + /* public key*/ + json_object_set (result, + "public_key", + json_object_get (arguments, + "public_key")); + + /* provider array */ + json_t *providers = json_object_get (arguments, + "providers"); + size_t num_of_providers = json_array_size (providers); + + /* go through each provider */ + json_t *temp_providers = json_array (); + for (size_t i = 0; i < num_of_providers; i++) + { + json_t *provider_i = json_array_get (providers, + i); + + json_t *temp_provider = json_object (); + + json_object_set (temp_provider, + "provider_name", + json_object_get (provider_i, + "provider_name")); + + json_object_set (temp_provider, + "backend_url", + json_object_get (provider_i, + "backend_url")); + + /* parse authentication data and compute salted hash */ + { + struct FROSIX_ChallengeHashP auth_hash; + /*const char *auth_method = NULL; + const char *auth_data = NULL; + const char *auth_answer = NULL; + struct GNUNET_HashCode auth_nonce; + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("auth_method", + &auth_method), + GNUNET_JSON_spec_string ("auth_data", + &auth_data), + GNUNET_JSON_spec_fixed_auto ("auth_nonce", + &auth_nonce), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("auth_answer", + &auth_answer), + NULL), + GNUNET_JSON_spec_end () + };*/ + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("auth_hash", + &auth_hash), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != GNUNET_JSON_parse (provider_i, + spec, + NULL, + NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + return; + } + + /*FROSIX_compute_auth_hash (&auth_hash, + auth_data, + &auth_nonce);*/ + + json_t *j_hash; + j_hash = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("auth_hash", + &auth_hash)); + + json_object_update_new (temp_provider, + j_hash); + + GNUNET_JSON_parse_free (spec); + } + + + json_object_set (temp_provider, + "provider_signature", + json_object_get (provider_i, + "provider_signature")); + + json_object_set (temp_provider, + "provider_public_key", + json_object_get (provider_i, + "provider_public_key")); + + json_array_append_new (temp_providers, + temp_provider); + } + + json_object_set_new (result, + "providers", + temp_providers); + + enum TALER_ErrorCode error_code = TALER_EC_NONE; + cb (cb_cls, + error_code, + result); +} + + +enum GNUNET_GenericReturnValue +FROSIX_verify_public_key (const json_t *arguments) +{ + struct FROST_PublicKey pk; + json_t *providers; + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("public_key", + &pk), + GNUNET_JSON_spec_json ("providers", + &providers), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != GNUNET_JSON_parse (arguments, + spec, + NULL, + NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + return GNUNET_NO; + } + + unsigned int len = json_array_size (providers); + + for (unsigned int i = 0; i < len; i++) + { + struct FROSIX_ChallengeHashP ch; + struct GNUNET_CRYPTO_EddsaSignature sig; + struct GNUNET_CRYPTO_EddsaPublicKey provider_pk; + + struct GNUNET_JSON_Specification provider_spec[] = { + GNUNET_JSON_spec_fixed_auto ("auth_hash", + &ch), + GNUNET_JSON_spec_fixed_auto ("provider_signature", + &sig), + GNUNET_JSON_spec_fixed_auto ("provider_public_key", + &provider_pk), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != GNUNET_JSON_parse (json_array_get (providers, + i), + provider_spec, + NULL, + NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (provider_spec); + GNUNET_JSON_parse_free (spec); + return GNUNET_NO; + } + + struct FROSIX_DkgKeySignaturePS ks = { + .purpose.purpose = htonl (104), + .purpose.size = htonl (sizeof (ks)), + .public_key = pk, + .auth_hash = ch, + }; + + if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify ( + 104, + &ks, + &sig, + &provider_pk)) + { + GNUNET_JSON_parse_free (provider_spec); + GNUNET_JSON_parse_free (spec); + return GNUNET_NO; + } + + GNUNET_JSON_parse_free (provider_spec); + } + + GNUNET_JSON_parse_free (spec); + return GNUNET_OK; +} +\ No newline at end of file diff --git a/src/libfrosix/frosix_api.h b/src/libfrosix/frosix_api.h @@ -0,0 +1,52 @@ +/* + This file is part of Frosix + Copyright (C) 2020, 2021 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file libfrosix/frosix_api.h + * @brief anastasis reducer api, internal data structures + * @author Christian Grothoff + * @author Dominik Meister + * @author Dennis Neufeld + */ +#ifndef FROSIX_API_REDUX_H +#define FROSIX_API_REDUX_H + +#include <jansson.h> + + +/** + * CURL context to be used by all operations. + */ +extern struct GNUNET_CURL_Context *FROSIX_REDUX_ctx_; + + +/** + * Function to return a json error response. + * + * @param cb callback to give error to + * @param cb_cls callback closure + * @param ec error code + * @param detail error detail + */ +void +FROSIX_redux_fail_ (FROSIX_ActionCallback cb, + void *cb_cls, + enum TALER_ErrorCode ec, + const char *detail); + + + + +#endif diff --git a/src/libfrosix/frosix_api_delete-key.c b/src/libfrosix/frosix_api_delete-key.c @@ -0,0 +1,340 @@ +/* + This file is part of Frosix + Copyright (C) 2020, 2021 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file reducer/frosix_api_delete-key.c + * @brief frosix reducer key delete api + * @author Christian Grothoff + * @author Dominik Meister + * @author Dennis Neufeld + * @author Joel Urech + */ + +#include "platform.h" +#include "frost_verify.h" +#include "frosix.h" +#include "frosix_api.h" +#include <taler/taler_merchant_service.h> + +/** + * FIXME +*/ +struct FROSIX_KeyDeleteProvider +{ + /** + * URL of the provider. + */ + char *backend_url; + + /** + * Encryption key + */ + struct FROSIX_EncryptionKey enc_key; +}; + +/** + * FIXME +*/ +struct FROSIX_KeyDeleteData +{ + /** + * Pointer to a list of providers, length is @e num_of_providers + */ + struct FROSIX_KeyDeleteProvider *providers; + + /** + * How many providers do we have? + */ + uint8_t num_of_providers; +}; + + +/** + * State of a sign procedure +*/ +struct FROSIX_KeyDeleteState +{ + /** + * FIXME + */ + struct FROSIX_KeyDeleteData *key_del_data; + + /** + * Function to call when we are done. + */ + FROSIX_ActionCallback cb; + + /** + * Closure for @e cb. + */ + void *cb_cls; + + /** + * Redux action we returned to our controller. + */ + struct FROSIX_ReduxAction ra; + + /** + * Number of provider /config operations in @e ba_head that + * are still awaiting completion. + */ + uint8_t counter; + + /** + * Last error code + */ + enum TALER_ErrorCode error_code; + + /** + * Array of config requests, with length `num_of_participants` + */ + struct FROSIX_KeyDeleteOperation **kdo; +}; + + +/** + * Function to free all initialized memory of a provider from a + * `struct FROSIX_KeyDeleteProvider` + * + * @param fp the struct to clean up +*/ +static void +free_provider_struct (struct FROSIX_KeyDeleteProvider *kp) +{ + if (NULL != kp->backend_url) + GNUNET_free (kp->backend_url); +} + + +/** + * Function to free all initialized memory of a provider from a + * `struct FROSIX_KeyDeleteData` + * + * @param dd the struct to clean up +*/ +static void +free_data_struct (struct FROSIX_KeyDeleteData *dd) +{ + if (NULL != dd->providers) + { + for (unsigned int i = 0; i < dd->num_of_providers; i++) + { + if (NULL != &dd->providers[i]) + free_provider_struct (&dd->providers[i]); + } + + GNUNET_free (dd->providers); + } + + GNUNET_free (dd); +} + + +/** + * Function called when signature process is being aborted. + * Frees all initialized memory! + * + * @param cls a `struct FROSIX_KeyDeleteState` +*/ +static void +key_delete_cancel_cb (void *cls) +{ + struct FROSIX_KeyDeleteState *kds = cls; + + if (NULL != kds->key_del_data) + free_data_struct (kds->key_del_data); + + /* free operations */ + if (NULL != kds->kdo) + GNUNET_free (kds->kdo); + + GNUNET_free (kds); +} + + +/** + * Callback to process a POST /sig-commitment request + * + * @param cls closure + * @param scd the decoded response body +*/ +static void +key_delete_request_cb ( + void *cls, + const struct FROSIX_KeyDeleteDetails *kdd) +{ + GNUNET_assert (NULL != cls); + struct FROSIX_KeyDeleteState *kds = cls; + + /* set error code */ + kds->error_code = kdd->ec; + + /* check if this is a valid callback */ + GNUNET_assert (0 < kds->counter); + GNUNET_assert (0 != kdd->http_status); + + /* call next dkg-commitment request */ + kds->counter--; + if (0 == kds->counter) + { + /* we are the last, go ahead with sig-share */ + free_data_struct (kds->key_del_data); + + kds->cb (kds->cb_cls, + kds->error_code, + NULL); + } +} + + +/** + * FIXME +*/ +static void +start_key_delete (struct FROSIX_KeyDeleteState *kds) +{ + kds->kdo = GNUNET_malloc ( + kds->key_del_data->num_of_providers * sizeof (char *)); + + kds->counter = 0; + for (unsigned int i = 0; i < kds->key_del_data->num_of_providers; i++) + { + struct FROSIX_KeyDeleteProvider *kp = &kds->key_del_data->providers[i]; + + /* hash encryption key to get request id*/ + struct FROSIX_DkgRequestIdP request_id; + FROSIX_hash_encryption_key (&request_id.id, + &kp->enc_key); + + kds->kdo[i] = FROSIX_key_delete ( + FROSIX_REDUX_ctx_, + kp->backend_url, + &request_id, + &key_delete_request_cb, + kds); + + kds->counter++; + } +} + + +/** + * Helper function to parse a keygen input + * + * @param[in,out] kdd A initialized struct + * @param[in] input Input from the cli +*/ +enum GNUNET_GenericReturnValue +parse_key_delete_input (struct FROSIX_KeyDeleteData *kdd, + const json_t *input) +{ + json_t *providers = NULL; + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_uint8 ("number_of_participants", + &kdd->num_of_providers), + GNUNET_JSON_spec_json ("providers", + &providers), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != GNUNET_JSON_parse (input, + spec, + NULL, + NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + return GNUNET_NO; + } + + /* get number of providers */ + size_t parsed_providers_len = json_array_size (providers); + + /* validate number of providers */ + GNUNET_assert (kdd->num_of_providers == parsed_providers_len); + GNUNET_assert (254 > kdd->num_of_providers); + GNUNET_assert (1 < kdd->num_of_providers); + + /* initialize providers */ + kdd->providers = GNUNET_new_array (kdd->num_of_providers, + struct FROSIX_KeyDeleteProvider); + + /* parse provider data */ + for (unsigned int i = 0; i < kdd->num_of_providers; i++) + { + struct GNUNET_JSON_Specification prov_spec[] = { + GNUNET_JSON_spec_string ("backend_url", + (const + char**) &kdd->providers[i].backend_url), + GNUNET_JSON_spec_fixed_auto ("encryption_key", + &kdd->providers[i].enc_key), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != GNUNET_JSON_parse (json_array_get (providers, + i), + prov_spec, + NULL, + NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (prov_spec); + GNUNET_JSON_parse_free (spec); + return GNUNET_NO; + } + + GNUNET_JSON_parse_free (prov_spec); + } + + GNUNET_JSON_parse_free (spec); + + return GNUNET_OK; +} + +/** + * +*/ +struct FROSIX_ReduxAction * +FROSIX_redux_key_delete_start (json_t *input, + FROSIX_ActionCallback cb, + void *cb_cls) +{ + struct FROSIX_KeyDeleteData *key_del_data = GNUNET_new (struct + FROSIX_KeyDeleteData); + + /* parse arguments from cli */ + if (GNUNET_OK != parse_key_delete_input (key_del_data, + input)) + { + free_data_struct (key_del_data); + + // FIXME: Return some useful error message + return NULL; + } + + struct FROSIX_KeyDeleteState *kds = GNUNET_new (struct FROSIX_KeyDeleteState); + + kds->cb = cb; + kds->cb_cls = cb_cls; + kds->key_del_data = key_del_data; + kds->ra.cleanup = &key_delete_cancel_cb; + kds->ra.cleanup_cls = kds; + + /* get commitments from all parsed providers */ + start_key_delete (kds); + + return &kds->ra; +} +\ No newline at end of file diff --git a/src/libfrosix/frosix_api_keygen.c b/src/libfrosix/frosix_api_keygen.c @@ -0,0 +1,1278 @@ +/* + This file is part of Frosix + Copyright (C) 2020, 2021 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file reducer/frosix_api_keygen.c + * @brief frosix reducer keygen api + * @author Christian Grothoff + * @author Dominik Meister + * @author Dennis Neufeld + * @author Joel Urech + */ + +#include "platform.h" +#include "frosix.h" +#include "frosix_api.h" +#include <taler/taler_merchant_service.h> +#include <time.h> + +#define FROSIX_KDF_CONTEXT "FROSIX-KEY" + +/** + * FIXME +*/ +struct FROSIX_DkgProvider +{ + /** + * Name of the provider + */ + char *provider_name; + + /** + * URL of the provider. + */ + char *backend_url; + + /** + * Public provider salt + */ + struct FROSIX_ProviderSaltP provider_salt; + + /** + * Long term public key of the provider + */ + struct GNUNET_CRYPTO_EddsaPublicKey provider_public_key; + + /** + * Index of the provider + */ + uint8_t provider_index; + + /** + * Authentication method. + */ + char *auth_method; + + /** + * Authentication data. + */ + char *auth_data; + + /** + * Answer to the question in @e auth_data. + * This field is optional and only used if authentication method is of type + * security question. + */ + char *auth_answer; + + /** + * Context String for this provider. + */ + struct FROSIX_DkgContextStringP context_string; + + /** + * Salt for the hash of the authentication data + */ + struct GNUNET_HashCode hash_salt; + + /** + * Salted hash of the challenge data + */ + struct FROSIX_ChallengeHashP auth_hash; + + /** + * Commitments which we get from round 1 + */ + struct FROSIX_DkgCommitment commitment; + + /** + * Pre encryption key + */ + struct FROSIX_EncryptionKey pre_enc_key; + + /** + * All the secret shares received from this provider. + * Number or length of this array is always `number_of_participants - 1` + */ + struct FROSIX_DkgSecretShare *secret_shares; + + /** + * Public key, should be the same at all providers + */ + struct FROST_PublicKey public_key; + + /** + * Provider's signature over public key and authentication data. + */ + struct GNUNET_CRYPTO_EddsaSignature providers_signature; + + /** + * Seed of provider + */ + uint8_t seed[64]; +}; + + +/** + * Struct to store all parsed data from the cli and /config and /seed +*/ +struct FROSIX_DkgData +{ + /** + * What is the threshold value? + */ + uint8_t threshold; + + /** + * Number of participating providers. Is the length of the @e providers array + */ + uint8_t num_of_participants; + + /** + * Our master key we have to export at the end of the DKG. + */ + struct GNUNET_HashCode master_key; + + /** + * Pointer to a list of providers + */ + struct FROSIX_DkgProvider *providers; + + /** + * Array of the public keys from all providers. + * Length is @e num_of_participants + */ + struct GNUNET_CRYPTO_EddsaPublicKey *providers_public_keys; + + /** + * Number of years the key data should be stored at the providers. + */ + uint64_t expiration; +}; + + +/** + * State of a keygen procedure +*/ +struct FROSIX_DkgState +{ + /** + * State we are updating. + */ + struct FROSIX_DkgData *dkg_data; + + /** + * Function to call when we are done. + */ + FROSIX_ActionCallback cb; + + /** + * Closure for @e cb. + */ + void *cb_cls; + + /** + * Redux action we returned to our controller. + */ + struct FROSIX_ReduxAction ra; + + /** + * Number of provider operations that are still awaiting completion. + */ + uint8_t counter; + + /** + * Last error code + */ + enum TALER_ErrorCode error_code; + + /** + * Array of config requests, with length `num_of_participants` + */ + struct FROSIX_ConfigOperation **co; + + /** + * Array of seed requests, with length `num_of_participants` + */ + struct FROSIX_SeedGetOperation **sgo; + + /** + * DKG-Commitment Requests + */ + struct FROSIX_DkgCommitmentRequestOperation **dco; + + /** + * DKG-Share Requests + */ + struct FROSIX_DkgShareRequestOperation **dso; + + /** + * DKG-Key Requests + */ + struct FROSIX_DkgKeyStoreOperation **dko; +}; + + +/** + * Helper function to free all initialized memory of a + * `struct FROSIX_DkgProvider` + * + * @param dp Pointer to the provider we want to free the memory. +*/ +static void +free_dkg_provider_struct (struct FROSIX_DkgProvider *dp) +{ + if (NULL != dp->provider_name) + GNUNET_free (dp->provider_name); + + if (NULL != dp->backend_url) + GNUNET_free (dp->backend_url); + + if (NULL != dp->auth_method) + GNUNET_free (dp->auth_method); + + if (NULL != dp->auth_data) + GNUNET_free (dp->auth_data); + + if (NULL != dp->auth_answer) + GNUNET_free (dp->auth_answer); + + FROST_free_dkg_commitment (&dp->commitment.commitment, + 1); + + if (NULL != dp->secret_shares) + GNUNET_free (dp->secret_shares); +} + + +/** + * Function to free all initialized memory of a provider from a + * `struct FROSIX_DkgData` + * + * @param dd the struct to clean up +*/ +static void +free_dkg_data_struct (struct FROSIX_DkgData *dd) +{ + /* go through all providers - if any */ + if (NULL != dd->providers) + { + for (unsigned int i = 0; i < dd->num_of_participants; i++) + { + if (NULL != &dd->providers[i]) + free_dkg_provider_struct (&dd->providers[i]); + } + GNUNET_free (dd->providers); + } + + if (NULL != dd->providers_public_keys) + GNUNET_free (dd->providers_public_keys); + + GNUNET_free (dd); +} + + +/** + * Function called when keygen is being aborted. + * Frees all initialized memory! + * + * @param cls a `struct FROSIX_DkgState` +*/ +static void +keygen_cancel_cb (void *cls) +{ + struct FROSIX_DkgState *ds = cls; + + /* free dkg data */ + if (NULL != ds->dkg_data) + free_dkg_data_struct (ds->dkg_data); + + /* free operations */ + if (NULL != ds->co) + GNUNET_free (ds->co); + + if (NULL != ds->sgo) + GNUNET_free (ds->sgo); + + if (NULL != ds->dco) + GNUNET_free (ds->dco); + + if (NULL != ds->dso) + GNUNET_free (ds->dso); + + if (NULL != ds->dko) + GNUNET_free (ds->dko); + + /* free dkg state */ + GNUNET_free (ds); +} + + +/** + * FIXME: move to frosix common crypto functions library! +*/ +static void +derive_encryption_key ( + struct FROSIX_EncryptionKey *enc_key, + const struct FROSIX_EncryptionKey *pre_enc_key, + const struct FROST_PublicKey *pk, + const struct FROSIX_ProviderSaltP *provider_salt, + uint8_t provider_index) +{ + GNUNET_CRYPTO_kdf (enc_key, + sizeof (*enc_key), + FROSIX_KDF_CONTEXT, + sizeof (FROSIX_KDF_CONTEXT), + pre_enc_key, + sizeof (*pre_enc_key), + pk, + sizeof (*pk), + provider_salt, + sizeof (*provider_salt), + &provider_index, + sizeof (provider_index), + NULL, + 0); +} + +/** + * Helper function to build an array out of all provider public keys. + * The assembled array is then stored in our @a dd struct. + * + * @param dd Our main struct to store all relevant data in. +*/ +static void +keygen_build_public_key_array (struct FROSIX_DkgData *dd) +{ + /* prepare array of providers public keys */ + dd->providers_public_keys = GNUNET_malloc ( + dd->num_of_participants + * sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); + + GNUNET_assert (NULL != dd->providers_public_keys); + + for (unsigned int i = 0; i < dd->num_of_participants; i++) + { + memcpy (&dd->providers_public_keys[i], + &dd->providers[i].provider_public_key, + sizeof (dd->providers->provider_public_key)); + } +} + + +/** + * This function gets called after we have received a positive result from all + * providers. It prepares a json struct, which we then return back to the cli. + * + * @param ds The state of our keygen process. +*/ +static void +keygen_prepare_result (struct FROSIX_DkgState *ds) +{ + /* first check if signature from providers can be verified. */ + // FIXME: define constant for size of ps struct + for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) + { + struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[i]; + + struct FROSIX_DkgKeySignaturePS ks = { + .purpose.purpose = htonl (104), + .purpose.size = htonl (sizeof (ks)), + .public_key = dp->public_key, + .auth_hash = dp->auth_hash, + }; + + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_verify ( + 104, + &ks, + &dp->providers_signature, + &dp->provider_public_key)); + } + + /* check if every reported public key is the same */ + for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) + { + GNUNET_assert (FROST_point_cmp (&ds->dkg_data->providers[i].public_key.pk, + &ds->dkg_data->providers[0].public_key.pk)); + } + + /* calculate encryption keys */ + struct FROSIX_EncryptionKey enc_keys[ds->dkg_data->num_of_participants]; + for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) + { + struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[i]; + derive_encryption_key (&enc_keys[i], + &dp->pre_enc_key, + &dp->public_key, + &dp->provider_salt, + dp->provider_index); + } + + /* build json */ + json_t *result; + json_t *providers = json_array (); + + for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) + { + /* build single provider */ + struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[i]; + json_t *provider; + provider = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("provider_index", + dp->provider_index), + GNUNET_JSON_pack_string ("provider_name", + dp->provider_name), + GNUNET_JSON_pack_string ("backend_url", + dp->backend_url), + GNUNET_JSON_pack_data_auto ("encryption_key", + &enc_keys[i]), + GNUNET_JSON_pack_string ("auth_method", + dp->auth_method), + GNUNET_JSON_pack_string ("auth_data", + dp->auth_data), + GNUNET_JSON_pack_data_auto ("auth_nonce", + &dp->hash_salt), + GNUNET_JSON_pack_data_auto ("auth_hash", + &dp->auth_hash), + GNUNET_JSON_pack_data_auto ("provider_signature", + &dp->providers_signature), + GNUNET_JSON_pack_data_auto ("provider_public_key", + &dp->provider_public_key)); + + /* add to provider array */ + GNUNET_assert (0 == + json_array_append_new ( + providers, + provider)); + } + + + result = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("public_key", + &ds->dkg_data->providers[0].public_key), + GNUNET_JSON_pack_uint64 ("number_of_participants", + ds->dkg_data->num_of_participants), + GNUNET_JSON_pack_uint64 ("threshold", + ds->dkg_data->threshold), + GNUNET_JSON_pack_array_steal ("providers", + providers)); + + /* free all initialized data */ + free_dkg_data_struct (ds->dkg_data); + + ds->cb (ds->cb_cls, + ds->error_code, + result); +} + + +/** + * Callback to process a POST /dkg-key request + * + * @param cls closure + * @param dcd the decoded response body +*/ +static void +dkg_key_request_cb (void *cls, + const struct FROSIX_DkgKeyStoreDetails *dkd) +{ + GNUNET_assert (NULL != cls); + struct FROSIX_DkgState *ds = cls; + + /* set error code */ + ds->error_code = dkd->ec; + + /* check if this is a valid callback */ + GNUNET_assert (0 < ds->counter); + GNUNET_assert (0 != dkd->http_status); + + /* check if provider index is valid */ + GNUNET_assert (0 < dkd->provider_index); + GNUNET_assert (ds->dkg_data->num_of_participants >= dkd->provider_index); + + /* copy commitment in our struct - just assign pointer */ + struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[dkd->provider_index + - 1]; + + memcpy (&dp->public_key, + &dkd->details.public_key, + sizeof (dkd->details.public_key)); + + memcpy (&dp->providers_signature, + &dkd->details.signature, + sizeof (dkd->details.signature)); + + /* call next dkg-commitment request */ + ds->counter--; + if (0 == ds->counter) + { + /* we are the last, go ahead with checking our result */ + GNUNET_free (ds->dko); + ds->dko = NULL; + keygen_prepare_result (ds); + } +} + + +/** + * FIXME +*/ +static void +start_dkg_key (struct FROSIX_DkgState *ds) +{ + ds->dko = GNUNET_malloc (ds->dkg_data->num_of_participants * sizeof (char *)); + ds->counter = 0; + + for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) + { + struct FROSIX_DkgData *dd = ds->dkg_data; + struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[i]; + + /* set up array of secret shares */ + struct FROSIX_DkgKeyStoreShare secret_shares[dd->num_of_participants - 1]; + + for (unsigned int j = 0; j < dd->num_of_participants; j++) + { + if (j < i) + { + GNUNET_assert (dp->provider_index == + dd->providers[j].secret_shares[i - 1].target); + secret_shares[j].identifier = + dd->providers[j].secret_shares[i - 1].issuer; + // FIXME: memory problem? + memcpy (&secret_shares[j].secret_share, + &dd->providers[j].secret_shares[i - 1].encrypted_share, + sizeof (dd->providers[j].secret_shares[i - 1].encrypted_share)); + memcpy (&secret_shares[j].ephemeral_key, + &dd->providers[j].secret_shares[i - 1].ephemeral_key, + sizeof (dd->providers[j].secret_shares[i - 1].ephemeral_key)); + } + else if (j > i) + { + GNUNET_assert (dp->provider_index == + dd->providers[j].secret_shares[i].target); + secret_shares[j - 1].identifier = + dd->providers[j].secret_shares[i].issuer; + memcpy (&secret_shares[j - 1].secret_share, + &dd->providers[j].secret_shares[i].encrypted_share, + sizeof (dd->providers[j].secret_shares[i].encrypted_share)); + memcpy (&secret_shares[j - 1].ephemeral_key, + &dd->providers[j].secret_shares[i].ephemeral_key, + sizeof (dd->providers[j].secret_shares[i].ephemeral_key)); + } + } + + /* compute request id */ + struct FROSIX_DkgRequestIdP request_id; + FROSIX_compute_dkg_request_id ( + &request_id, + &dp->context_string, + &dp->auth_hash, + &dp->provider_salt, + dp->provider_index, + ds->dkg_data->num_of_participants, + ds->dkg_data->threshold); + + ds->dko[i] = FROSIX_dkg_key_store ( + FROSIX_REDUX_ctx_, + dp->backend_url, + &request_id, + dp->provider_index, + dd->threshold, + dd->num_of_participants, + &dp->context_string, + &dp->auth_hash, + dd->providers_public_keys, + &dp->pre_enc_key, + dd->expiration, + secret_shares, + dd->num_of_participants - 1, + &dkg_key_request_cb, + ds); + + ds->counter++; + } +} + + +/** + * Callback to process a POST /dkg-shares request + * + * @param cls closure + * @param dcd the decoded response body +*/ +static void +dkg_share_request_cb (void *cls, + const struct FROSIX_DkgShareRequestDetails *dsd) +{ + GNUNET_assert (NULL != cls); + struct FROSIX_DkgState *ds = cls; + + /* set error code */ + ds->error_code = dsd->ec; + + /* check if this is a valid callback */ + GNUNET_assert (0 < ds->counter); + GNUNET_assert (0 != dsd->http_status); + + /* check if provider index is valid */ + GNUNET_assert (0 < dsd->provider_index); + GNUNET_assert (ds->dkg_data->num_of_participants >= dsd->provider_index); + + /* check number of secret shares */ + GNUNET_assert (ds->dkg_data->num_of_participants - 1 == dsd->shares_len); + + /* check if our provider index is same as in the response */ + for (unsigned int i = 0; i < dsd->shares_len; i++) + { + GNUNET_assert (dsd->provider_index == dsd->shares[i].issuer); + } + + /* copy commitment in our struct - just assign pointer */ + ds->dkg_data->providers[dsd->provider_index - 1].secret_shares = dsd->shares; + + /* call next dkg-commitment request */ + ds->counter--; + if (0 == ds->counter) + { + /* we are the last, go ahead with dkg-key */ + GNUNET_free (ds->dso); + ds->dso = NULL; + start_dkg_key (ds); + } +} + + +/** + * FIXME +*/ +static void +start_dkg_shares (struct FROSIX_DkgState *ds) +{ + ds->dso = GNUNET_malloc (ds->dkg_data->num_of_participants * sizeof (char *)); + ds->counter = 0; + + for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) + { + struct FROSIX_DkgData *dd = ds->dkg_data; + struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[i]; + + /* set up array of dkg commitments */ + struct FROSIX_DkgCommitment dkg_commitments[dd->num_of_participants - 1]; + for (unsigned int j = 0; j < dd->num_of_participants; j++) + { + if (j < i) + { + dkg_commitments[j] = dd->providers[j].commitment; + } + else if (j > i) + { + dkg_commitments[j - 1] = dd->providers[j].commitment; + } + } + + /* compute request id */ + struct FROSIX_DkgRequestIdP request_id; + FROSIX_compute_dkg_request_id ( + &request_id, + &dp->context_string, + &dp->auth_hash, + &dp->provider_salt, + dp->provider_index, + ds->dkg_data->num_of_participants, + ds->dkg_data->threshold); + + ds->dso[i] = FROSIX_dkg_share_request ( + FROSIX_REDUX_ctx_, + dp->backend_url, + &request_id, + dp->provider_index, + dd->threshold, + dd->num_of_participants, + &dp->context_string, + &dp->auth_hash, + dkg_commitments, + dd->num_of_participants - 1, + dd->providers_public_keys, + &dkg_share_request_cb, + ds); + + ds->counter++; + } + + /* free dkg commitments */ + for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) + { + FROST_free_dkg_commitment ( + &ds->dkg_data->providers[i].commitment.commitment, + 1); + } +} + + +/** + * Callback to process a POST /dkg-commitment request + * + * @param cls closure + * @param dcd the decoded response body +*/ +static void +dkg_commitment_request_cb (void *cls, + const struct FROSIX_DkgCommitmentRequestDetails *dcd) +{ + GNUNET_assert (NULL != cls); + struct FROSIX_DkgState *ds = cls; + + /* set error code */ + ds->error_code = dcd->ec; + + /* check if this is a valid callback */ + GNUNET_assert (0 < ds->counter); + GNUNET_assert (0 != dcd->http_status); + + /* check if provider index is valid */ + GNUNET_assert (0 < dcd->provider_index); + GNUNET_assert (ds->dkg_data->num_of_participants >= dcd->provider_index); + + /* check if our provider index is same as in the response */ + GNUNET_assert (dcd->provider_index == dcd->dkg_commitment.identifier); + + /* check if length of commitments equals our threshold value */ + GNUNET_assert (dcd->dkg_commitment.shares_commitments_length == + ds->dkg_data->threshold); + + /* copy commitment in our struct */ + struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[dcd->provider_index + - 1]; + + /* Fill return values in our central struct */ + memcpy (&dp->commitment.encryption_public_key, + &dcd->public_key, + sizeof (dcd->public_key)); + + FROST_initialize_dkg_commitment ( + &dp->commitment.commitment, + dcd->provider_index, + dcd->dkg_commitment.shares_commitments_length); + + for (unsigned int i = 0; i < dcd->dkg_commitment.shares_commitments_length; + i++) + { + memcpy (&dp->commitment.commitment.share_comm[i], + &dcd->dkg_commitment.share_comm[i], + sizeof (dcd->dkg_commitment.share_comm[i])); + } + + memcpy (&dp->commitment.commitment.zkp.r, + &dcd->dkg_commitment.zkp.r, + sizeof (dcd->dkg_commitment.zkp.r)); + + memcpy (&dp->commitment.commitment.zkp.z, + &dcd->dkg_commitment.zkp.z, + sizeof (dcd->dkg_commitment.zkp.z)); + + /* call next dkg-commitment request */ + ds->counter--; + if (0 == ds->counter) + { + /* we are the last, go ahead with dkg-share */ + GNUNET_free (ds->dco); + ds->dco = NULL; + start_dkg_shares (ds); + } +} + + +/** + * Function to derive the master key and all context strings. + * + * @param[in,out] dd the struct to fill in the entropy + * @param[in] client_entropy high entropy bytes to derive more high entropy bytes +*/ +static void +keygen_derive_entropy (struct FROSIX_DkgData *dd, + const struct GNUNET_HashCode *client_entropy, + const struct GNUNET_HashCode *provider_entropy) +{ + { + /* derive high entropy bytes */ + size_t length = sizeof (dd->master_key) + + (dd->num_of_participants + * sizeof (dd->providers->context_string)); + + char *derived_entropy = GNUNET_malloc (length); + + /* kill process if allocation failed */ + GNUNET_assert (NULL != derived_entropy); + + GNUNET_assert (GNUNET_CRYPTO_kdf (derived_entropy, + length, + "FROSIX", + strlen ("FROSIX"), + client_entropy, + sizeof (*client_entropy), + provider_entropy, + sizeof (*provider_entropy), + NULL, + 0)); + + /* copy the derived bytes to the right place */ + unsigned int byte_counter = 0; + memcpy (&dd->master_key, + &derived_entropy[byte_counter], + sizeof (dd->master_key)); + byte_counter += sizeof (dd->master_key); + + for (unsigned int i = 0; i < dd->num_of_participants; i++) + { + memcpy (&dd->providers[i].context_string, + &derived_entropy[byte_counter], + sizeof (dd->providers->context_string)); + byte_counter += sizeof (dd->providers->context_string); + } + + /* free allocated memory */ + GNUNET_free (derived_entropy); + } + + { + /* derive authentication salts and pre encryption keys */ + size_t length = dd->num_of_participants + * (sizeof (dd->providers->hash_salt) + + sizeof (dd->providers->pre_enc_key)); + + char *client_entropy = GNUNET_malloc (length); + + /* kill process if allocation failed */ + GNUNET_assert (NULL != client_entropy); + + GNUNET_CRYPTO_kdf (client_entropy, + length, + "FROSIX", + strlen ("FROSIX"), + &dd->master_key, + sizeof (dd->master_key), + NULL, + 0); + + /* copy bytes to the right place */ + unsigned int byte_counter = 0; + for (unsigned int i = 0; i < dd->num_of_participants; i++) + { + memcpy (&dd->providers[i].hash_salt, + &client_entropy[byte_counter], + sizeof (dd->providers->hash_salt)); + byte_counter += sizeof (dd->providers->hash_salt); + } + + for (unsigned int i = 0; i < dd->num_of_participants; i++) + { + memcpy (&dd->providers[i].pre_enc_key, + &client_entropy[byte_counter], + sizeof (dd->providers->pre_enc_key)); + byte_counter += sizeof (dd->providers->pre_enc_key); + } + + /* free allocated memory */ + GNUNET_free (client_entropy); + } +} + + +/** + * FIXME +*/ +static void +merge_provider_entropy (struct GNUNET_HashCode *provider_entropy, + const struct FROSIX_DkgState *ds) +{ + struct GNUNET_HashContext *hc = GNUNET_CRYPTO_hash_context_start (); + for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) + { + GNUNET_CRYPTO_hash_context_read (hc, + ds->dkg_data->providers[i].seed, + sizeof (ds->dkg_data->providers[i].seed)); + } + + GNUNET_CRYPTO_hash_context_finish (hc, + provider_entropy); +} + + +/** + * FIXME +*/ +static void +start_dkg_commitments (struct FROSIX_DkgState *ds) +{ + /* measure cpu speed */ + // unsigned int target_difficulty = 5000; // FIXME + unsigned int amplifier = 1; + { + struct FROST_PowSalt salt; + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, + &salt, + sizeof (salt)); + + /* start */ + // clock_t start = clock (); + struct FROST_HashCode hash; + FROST_pow_hash (&hash, + "Frosix", + strlen ("Frosix"), + &salt, + 1); + /* end */ + // clock_t end = clock (); + // float seconds = (float) (end - start) / 1000; + // amplifier = target_difficulty / seconds; + + } + + /* merge provider seeds to a single hash code */ + struct GNUNET_HashCode provider_entropy; + merge_provider_entropy (&provider_entropy, + ds); + + /* derive master key, context strings, salts and pre encryption keys */ + struct GNUNET_HashCode client_entropy; + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, + &client_entropy, + sizeof (client_entropy)); + + keygen_derive_entropy (ds->dkg_data, + &client_entropy, + &provider_entropy); + + /* computer salted hash of authentication data */ + for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) + { + struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[i]; + if (NULL != dp->auth_answer) + { + /* we have a security question here */ + struct GNUNET_CRYPTO_Edx25519PrivateKey priv; + struct GNUNET_CRYPTO_Edx25519PublicKey pub; + FROSIX_hash_pow (&dp->auth_hash.hash, + &priv, + &pub, + &dp->hash_salt, + dp->auth_answer, + amplifier); + } + else + { + FROSIX_compute_auth_hash (&dp->auth_hash, + dp->auth_data, + &dp->hash_salt); + } + } + + ds->dco = GNUNET_malloc (ds->dkg_data->num_of_participants * sizeof (char *)); + ds->counter = 0; + + for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) + { + struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[i]; + + /* compute request id */ + struct FROSIX_DkgRequestIdP request_id; + FROSIX_compute_dkg_request_id ( + &request_id, + &dp->context_string, + &dp->auth_hash, + &dp->provider_salt, + dp->provider_index, + ds->dkg_data->num_of_participants, + ds->dkg_data->threshold); + + ds->dco[i] = FROSIX_dkg_commitment_request ( + FROSIX_REDUX_ctx_, + dp->backend_url, + &request_id, + dp->provider_index, + ds->dkg_data->threshold, + ds->dkg_data->num_of_participants, + &dp->context_string, + &dp->auth_hash, + ds->dkg_data->providers_public_keys, + &dkg_commitment_request_cb, + ds); + + ds->counter++; + } +} + + +/** + Callback to process a GET /seed request + * + * @param cls closure + * @param ps the decoded response body +*/ +static void +seed_request_cb (void *cls, + unsigned int http_status, + const struct FROSIX_ProviderSeed *ps) +{ + GNUNET_assert (NULL != cls); + struct FROSIX_DkgState *ds = cls; + + /* check if this is a valid callback */ + GNUNET_assert (0 < ds->counter); + GNUNET_assert (0 != http_status); + + /* check if provider index is valid */ + GNUNET_assert (0 < ps->provider_index); + GNUNET_assert (ds->dkg_data->num_of_participants >= ps->provider_index); + + /* copy seed to our main struct */ + struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[ps->provider_index + - 1]; + + memcpy (&dp->seed, + ps->seed, + FROSIX_SEED_SIZE); + + ds->counter--; + if (0 == ds->counter) + { + GNUNET_free (ds->sgo); + ds->sgo = NULL; + /* we are the last, go ahead with dkg-commitment */ + start_dkg_commitments (ds); + } +} + + +/** + * FIXME +*/ +static void +start_seed_requests (struct FROSIX_DkgState *ds) +{ + ds->counter = 0; + // FIXME: pointer to array of pointers? + ds->sgo = GNUNET_malloc (ds->dkg_data->num_of_participants * sizeof (char *)); + // FIXME: implement free of config operations + for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) + { + ds->sgo[i] = FROSIX_seed_get (FROSIX_REDUX_ctx_, + ds->dkg_data->providers[i].backend_url, + i + 1, + &seed_request_cb, + ds); + ds->counter++; + } +} + + +/** + * Callback to process a GET /config request + * + * @param cls closure + * @param fcfg the decoded response body +*/ +static void +config_request_cb (void *cls, + unsigned int http_status, + const struct FROSIX_Config *fcfg) +{ + GNUNET_assert (NULL != cls); + struct FROSIX_DkgState *ds = cls; + + /* check if this is a valid callback */ + GNUNET_assert (0 < ds->counter); // FIXME: abort correctly + GNUNET_assert (0 != http_status); + + /* check if provider index is valid */ + GNUNET_assert (0 < fcfg->provider_index); + GNUNET_assert (ds->dkg_data->num_of_participants >= fcfg->provider_index); + + { + /* copy config data to our main struct */ + struct FROSIX_DkgProvider *dp = + &ds->dkg_data->providers[fcfg->provider_index - 1]; + + dp->provider_name = strdup (fcfg->business_name); + + memcpy (&dp->provider_salt, + &fcfg->provider_salt, + sizeof (fcfg->provider_salt)); + + memcpy (&dp->provider_public_key, + &fcfg->public_key, + sizeof (fcfg->public_key)); + } + + ds->counter--; + if (0 == ds->counter) + { + GNUNET_free (ds->co); + ds->co = NULL; + + /* we are the last, build array of public keys + and go ahead with the seeds */ + keygen_build_public_key_array (ds->dkg_data); + + start_seed_requests (ds); + } +}; + + +/** + * FIXME +*/ +static void +start_config_requests (struct FROSIX_DkgState *ds) +{ + ds->counter = 0; + // FIXME: pointer to array of pointers? + ds->co = GNUNET_malloc (ds->dkg_data->num_of_participants * sizeof (char *)); + + for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) + { + ds->dkg_data->providers[i].provider_index = i + 1; + ds->co[i] = FROSIX_get_config (FROSIX_REDUX_ctx_, + ds->dkg_data->providers[i].backend_url, + i + 1, + &config_request_cb, + ds); + ds->counter++; + } +} + + +/** + * Helper function to parse a keygen input + * + * @param[in,out] dkg_data A initialized struct + * @param[in] arguments Input from the cli +*/ +enum GNUNET_GenericReturnValue +parse_keygen_arguments (struct FROSIX_DkgData *dkg_data, + const json_t *arguments) +{ + json_t *providers = NULL; + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_uint8 ("threshold", + &dkg_data->threshold), + GNUNET_JSON_spec_uint64 ("expiration", + &dkg_data->expiration), + GNUNET_JSON_spec_json ("providers", + &providers), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != GNUNET_JSON_parse (arguments, + spec, + NULL, + NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + return GNUNET_NO; + } + + /* get number of providers */ + size_t num_of_providers = json_array_size (providers); + + /* validate number of providers */ + GNUNET_assert (255 > num_of_providers); + GNUNET_assert (1 < num_of_providers); + GNUNET_assert (0 < dkg_data->threshold); + GNUNET_assert (num_of_providers > dkg_data->threshold); + + dkg_data->num_of_participants = num_of_providers; + + /* initialize providers */ + dkg_data->providers = GNUNET_new_array (dkg_data->num_of_participants, + struct FROSIX_DkgProvider); + + /* parse provider data */ + for (unsigned int i = 0; i < dkg_data->num_of_participants; i++) + { + struct GNUNET_JSON_Specification prov_spec[] = { + GNUNET_JSON_spec_string ("url", + (const + char**) &dkg_data->providers[i].backend_url), + GNUNET_JSON_spec_fixed_auto ("public_key", + &dkg_data->providers[i].provider_public_key), + GNUNET_JSON_spec_string ("auth_method", + (const + char**) &dkg_data->providers[i].auth_method), + GNUNET_JSON_spec_string ("auth_data", + (const + char**) &dkg_data->providers[i].auth_data), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("auth_answer", + (const + char**) &dkg_data->providers[i].auth_answer), + NULL), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != GNUNET_JSON_parse (json_array_get (providers, + i), + prov_spec, + NULL, + NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (prov_spec); + GNUNET_JSON_parse_free (spec); + return GNUNET_NO; + } + + GNUNET_JSON_parse_free (prov_spec); + } + + GNUNET_JSON_parse_free (spec); + return GNUNET_OK; +} + + +struct FROSIX_ReduxAction * +FROSIX_redux_keygen_start (const json_t *arguments, + FROSIX_ActionCallback cb, + void *cb_cls) +{ + /* initialize dkg data struct */ + struct FROSIX_DkgData *dkg_data = GNUNET_new (struct FROSIX_DkgData); + + /* parse arguments from cli */ + if (GNUNET_OK != parse_keygen_arguments (dkg_data, + arguments)) + { + free_dkg_data_struct (dkg_data); + + // FIXME: Return some useful error message + return NULL; + } + + /* lets create a state */ + struct FROSIX_DkgState *ds = GNUNET_new (struct FROSIX_DkgState); + ds->cb = cb; + ds->cb_cls = cb_cls; + ds->dkg_data = dkg_data; + ds->ra.cleanup = &keygen_cancel_cb; + ds->ra.cleanup_cls = ds; + + /* get configs from all parsed providers */ + start_config_requests (ds); + + return &ds->ra; +} +\ No newline at end of file diff --git a/src/libfrosix/frosix_api_request-challenge.c b/src/libfrosix/frosix_api_request-challenge.c @@ -0,0 +1,395 @@ +/* + This file is part of Frosix + Copyright (C) 2020, 2021 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file reducer/frosix_api_authenticate.c + * @brief frosix reducer sign api + * @author Christian Grothoff + * @author Dominik Meister + * @author Dennis Neufeld + * @author Joel Urech + */ + +#include "platform.h" +#include "frost_verify.h" +#include "frosix.h" +#include "frosix_api.h" +#include <taler/taler_merchant_service.h> + + +/** + * FIXME +*/ +struct FROSIX_Provider +{ + /** + * URL of the provider. + */ + char *backend_url; + + /** + * Index of the provider + */ + uint8_t provider_index; + + /** + * Authentication method. + */ + char *auth_method; + + /** + * Authentication data. + */ + char *auth_data; + + /** + * Salt for the hash of the authentication data + */ + struct GNUNET_HashCode auth_nonce; + + /** + * Encryption key + */ + struct FROSIX_EncryptionKey enc_key; +}; + +/** + * Struct to store all parsed data from the cli and /config and /seed +*/ +struct FROSIX_ChallengeRequestData +{ + /** + * Our hashed message. + */ + struct FROST_MessageHash message_hash; + + /** + * Our provider + */ + struct FROSIX_Provider provider; +}; + +/** + * State of a challenge request procedure +*/ +struct FROSIX_ChallengeRequestState +{ + /** + * State we are updating. + */ + struct FROSIX_ChallengeRequestData *challenge_data; + + /** + * Function to call when we are done. + */ + FROSIX_ActionCallback cb; + + /** + * Closure for @e cb. + */ + void *cb_cls; + + /** + * Redux action we returned to our controller. + */ + struct FROSIX_ReduxAction ra; + + /** + * Last error code + */ + enum TALER_ErrorCode error_code; + + /** + * Response as JSON + */ + json_t *response; + + /** + * Pointer to our AuthChallengeRequestOperation + */ + struct FROSIX_ChallengeRequestOperation *ao; +}; + + +/** + * Function to free all initialized memory of a provider from a + * `struct FROSIX_Provider` + * + * @param fp the struct to clean up +*/ +static void +free_provider_struct (struct FROSIX_Provider *fp) +{ + if (NULL != fp->backend_url) + GNUNET_free (fp->backend_url); + + if (NULL != fp->auth_method) + GNUNET_free (fp->auth_method); + + if (NULL != fp->auth_data) + GNUNET_free (fp->auth_data); +} + + +/** + * Function to free all initialized memory of a provider from a + * `struct FROSIX_SignatureData` + * + * @param dd the struct to clean up +*/ +static void +free_challenge_request_data_struct (struct FROSIX_ChallengeRequestData *cd) +{ + free_provider_struct (&cd->provider); + GNUNET_free (cd); +} + + +/** + * Function called when challenge-request process is being aborted. + * Frees all initialized memory! + * + * @param cls a `struct FROSIX_ChallengeRequestState` +*/ +static void +challenge_request_cancel_cb (void *cls) +{ + struct FROSIX_ChallengeRequestState *cs = cls; + + if (NULL != cs->challenge_data) + free_challenge_request_data_struct (cs->challenge_data); + + /* free operations */ + if (NULL != cs->ao) + GNUNET_free (cs->ao); + + GNUNET_free (cs); +} + + +/** + * FIXME +*/ +static void +return_feedback (struct FROSIX_ChallengeRequestState *cs) +{ + /* free all initialized data*/ + free_challenge_request_data_struct (cs->challenge_data); + + /* return empty */ + cs->cb (cs->cb_cls, + cs->error_code, + cs->response); +} + + +/** + * Callback to process a POST /auth-challenge request + * + * @param cls closure + * @param scd the decoded response body +*/ +static void +challenge_request_cb (void *cls, + const struct FROSIX_ChallengeRequestDetails *crd) +{ + GNUNET_assert (NULL != cls); + struct FROSIX_ChallengeRequestState *cs = cls; + + /* set error code */ + cs->error_code = crd->ec; + cs->response = json_deep_copy (crd->response); + + /* call callback and give a return message to the user */ + return_feedback (cs); +} + + +/** + * FIXME +*/ +static void +start_challenge_request (struct FROSIX_ChallengeRequestState *cs) +{ + /* calculate request id*/ + struct FROSIX_ChallengeRequestIdP request_id; + FROSIX_compute_challenge_request_id ( + &request_id, + &cs->challenge_data->provider.enc_key, + &cs->challenge_data->message_hash); + + cs->ao = FROSIX_auth_challenge_post ( + FROSIX_REDUX_ctx_, + cs->challenge_data->provider.backend_url, + &request_id, + &cs->challenge_data->provider.enc_key, + cs->challenge_data->provider.auth_method, + cs->challenge_data->provider.auth_data, + &cs->challenge_data->provider.auth_nonce, + &cs->challenge_data->message_hash, + &challenge_request_cb, + cs); +} + + +/** + * Helper function to parse a keygen input + * + * @param[in,out] dkg_data A initialized struct + * @param[in] arguments Input from the cli +*/ +enum GNUNET_GenericReturnValue +parse_challenge_request_arguments ( + struct FROSIX_ChallengeRequestData *challenge_data, + const json_t *arguments, + const json_t *input) +{ + json_t *providers = NULL; + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_json ("providers", + &providers), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != GNUNET_JSON_parse (arguments, + spec, + NULL, + NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + return GNUNET_NO; + } + + /* check number of parsed providers */ + size_t max_num = json_array_size (providers); + + /* enforce that only one provider is selected */ + GNUNET_assert (1 == json_object_size (input)); + + struct GNUNET_JSON_Specification selection_spec[] = { + GNUNET_JSON_spec_uint8 ("provider_index", + &challenge_data->provider.provider_index), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != GNUNET_JSON_parse (input, + selection_spec, + NULL, + NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (selection_spec); + GNUNET_JSON_parse_free (spec); + return GNUNET_NO; + } + + GNUNET_JSON_parse_free (selection_spec); + + /* check if our selected provider is in the keyfile */ + GNUNET_assert (max_num > challenge_data->provider.provider_index); + GNUNET_assert (0 < challenge_data->provider.provider_index); + uint8_t parsed_provider_index; + + /* parse provider data */ + struct GNUNET_JSON_Specification prov_spec[] = { + GNUNET_JSON_spec_uint8 ("provider_index", + &parsed_provider_index), + GNUNET_JSON_spec_string ( + "backend_url", + (const char**) &challenge_data->provider.backend_url), + GNUNET_JSON_spec_fixed_auto ("encryption_key", + &challenge_data->provider.enc_key), + GNUNET_JSON_spec_string ( + "auth_method", + (const char**) &challenge_data->provider.auth_method), + GNUNET_JSON_spec_string ( + "auth_data", + (const char**) &challenge_data->provider.auth_data), + GNUNET_JSON_spec_fixed_auto ("auth_nonce", + &challenge_data->provider.auth_nonce), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != GNUNET_JSON_parse ( + json_array_get ( + providers, + challenge_data->provider.provider_index - 1), + prov_spec, + NULL, + NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (prov_spec); + GNUNET_JSON_parse_free (spec); + return GNUNET_NO; + } + + GNUNET_JSON_parse_free (prov_spec); + GNUNET_JSON_parse_free (spec); + + /* check if parsed provider has correct index */ + GNUNET_assert (parsed_provider_index == + challenge_data->provider.provider_index); + + return GNUNET_OK; +} + + +/** + * +*/ +struct FROSIX_ReduxAction * +FROSIX_redux_challenge_request_start (const json_t *arguments, + const json_t *input, + const char *message, + FROSIX_ActionCallback cb, + void *cb_cls) +{ + /* initialize signature data struct */ + struct FROSIX_ChallengeRequestData *challenge_data = + GNUNET_new (struct FROSIX_ChallengeRequestData); + + /* parse arguments from cli */ + if (GNUNET_OK != parse_challenge_request_arguments (challenge_data, + arguments, + input)) + { + free_challenge_request_data_struct (challenge_data); + + // FIXME: Return some useful error message + return NULL; + } + + /* hash message */ + FROST_message_to_hash (&challenge_data->message_hash, + message, + strlen (message)); + + /* lets create a state */ + struct FROSIX_ChallengeRequestState *cs = GNUNET_new (struct + FROSIX_ChallengeRequestState); + cs->cb = cb; + cs->cb_cls = cb_cls; + cs->challenge_data = challenge_data; + cs->ra.cleanup = &challenge_request_cancel_cb; + cs->ra.cleanup_cls = cs; + + /* get commitments from all parsed providers */ + start_challenge_request (cs); + + return &cs->ra; +} +\ No newline at end of file diff --git a/src/libfrosix/frosix_api_sign.c b/src/libfrosix/frosix_api_sign.c @@ -0,0 +1,792 @@ +/* + This file is part of Frosix + Copyright (C) 2020, 2021 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file reducer/frosix_api_sign_redux.c + * @brief frosix reducer sign api + * @author Christian Grothoff + * @author Dominik Meister + * @author Dennis Neufeld + * @author Joel Urech + */ + +#include "platform.h" +#include "frost_verify.h" +#include "frosix.h" +#include "frosix_api.h" +#include <taler/taler_merchant_service.h> + + +/** + * FIXME +*/ +struct FROSIX_Provider +{ + /** + * URL of the provider. + */ + char *backend_url; + + /** + * Index of the provider + */ + uint8_t provider_index; + + /** + * Authentication data. + */ + struct GNUNET_HashCode auth_data; + + /** + * + */ + struct GNUNET_CRYPTO_Edx25519PublicKey auth_pub; + + /** + * + */ + struct GNUNET_CRYPTO_Edx25519Signature auth_sig; + + /** + * + */ + const char *auth_method; + + /** + * Encryption key + */ + struct FROSIX_EncryptionKey enc_key; + + /** + * Commitment for this signature process. + */ + struct FROST_Commitment commitment; + + /** + * The resulting signature share of this provider. + */ + struct FROST_SignatureShare sig_share; +}; + +/** + * Struct to store all parsed data from the cli and /config and /seed +*/ +struct FROSIX_SignatureData +{ + /** + * What is the threshold value? + */ + uint8_t threshold; + + /** + * Public key to verify the resulting signature + */ + struct FROST_PublicKey public_key; + + /** + * Our hashed message. + */ + struct FROST_MessageHash message_hash; + + /** + * Pointer to a list of providers, length is @e threshold + */ + struct FROSIX_Provider *providers; + + /** + * Resulting signature + */ + struct FROST_Signature signature; +}; + +/** + * State of a sign procedure +*/ +struct FROSIX_SignatureState +{ + /** + * State we are updating. + */ + struct FROSIX_SignatureData *sig_data; + + /** + * Function to call when we are done. + */ + FROSIX_ActionCallback cb; + + /** + * Closure for @e cb. + */ + void *cb_cls; + + /** + * Redux action we returned to our controller. + */ + struct FROSIX_ReduxAction ra; + + /** + * Number of provider /config operations in @e ba_head that + * are still awaiting completion. + */ + uint8_t counter; + + /** + * Last error code + */ + enum TALER_ErrorCode error_code; + + /** + * Array of config requests, with length `num_of_participants` + */ + struct FROSIX_ConfigOperation **co; + + /** + * Array of signature commitment requests with length @e threshold. + */ + struct FROSIX_SigCommitmentRequestOperation **sco; + + /** + * Array of signature share requests with length @e threshold. + */ + struct FROSIX_SigShareRequestOperation **sso; + +}; + + +/** + * Function to free all initialized memory of a provider from a + * `struct FROSIX_Provider` + * + * @param fp the struct to clean up +*/ +static void +free_provider_struct (struct FROSIX_Provider *fp) +{ + if (NULL != fp->backend_url) + GNUNET_free (fp->backend_url); +} + + +/** + * Function to free all initialized memory of a provider from a + * `struct FROSIX_SignatureData` + * + * @param dd the struct to clean up +*/ +static void +free_signature_data_struct (struct FROSIX_SignatureData *sd) +{ + if (NULL != sd->providers) + { + for (unsigned int i = 0; i < sd->threshold; i++) + { + if (NULL != &sd->providers[i]) + free_provider_struct (&sd->providers[i]); + } + + GNUNET_free (sd->providers); + } + + GNUNET_free (sd); +} + + +/** + * Function called when signature process is being aborted. + * Frees all initialized memory! + * + * @param cls a `struct FROSIX_SignatureState` +*/ +static void +sign_cancel_cb (void *cls) +{ + struct FROSIX_SignatureState *ss = cls; + + if (NULL != ss->sig_data) + free_signature_data_struct (ss->sig_data); + + /* free operations */ + if (NULL != ss->co) + GNUNET_free (ss->co); + + if (NULL != ss->sco) + GNUNET_free (ss->sco); + + if (NULL != ss->sso) + GNUNET_free (ss->sso); + + GNUNET_free (ss); + +} + + +/** + * FIXME +*/ +static void +check_and_prepare_signature (const struct FROSIX_SignatureState *ss) +{ + /* build array of commitments - needed for verification */ + struct FROST_Commitment commitments[ss->sig_data->threshold]; + for (unsigned int i = 0; i < ss->sig_data->threshold; i++) + { + struct FROSIX_Provider *fp = &ss->sig_data->providers[i]; + + commitments[i].identifier = fp->commitment.identifier; + + memcpy (&commitments[i].hiding_commitment, + &fp->commitment.hiding_commitment, + sizeof (fp->commitment.hiding_commitment)); + + memcpy (&commitments[i].binding_commitment, + &fp->commitment.binding_commitment, + sizeof (fp->commitment.binding_commitment)); + } + + /* verify received signature share */ + for (unsigned int i = 0; i < ss->sig_data->threshold; i++) + { + struct FROSIX_Provider *fp = &ss->sig_data->providers[i]; + + GNUNET_assert (FROST_verify_signature_share ( + &fp->commitment, + &fp->sig_share, + commitments, + ss->sig_data->threshold, + &ss->sig_data->public_key, + &ss->sig_data->message_hash)); + } + + /* copy all signature shares together */ + struct FROST_SignatureShare sig_shares[ss->sig_data->threshold]; + for (unsigned int i = 0; i < ss->sig_data->threshold; i++) + { + struct FROSIX_Provider *fp = &ss->sig_data->providers[i]; + + sig_shares[i].identifier = fp->sig_share.identifier; + + memcpy (&sig_shares[i].sig_share, + &fp->sig_share.sig_share, + sizeof (fp->sig_share.sig_share)); + + memcpy (&sig_shares[i].pk_i, + &fp->sig_share.pk_i, + sizeof (fp->sig_share.pk_i)); + } + + /* build signature */ + FROST_compose_signature (&ss->sig_data->signature, + commitments, + sig_shares, + ss->sig_data->threshold, + &ss->sig_data->message_hash); + + /* verify signature */ + GNUNET_assert (FROST_verify_signature (&ss->sig_data->public_key, + &ss->sig_data->signature, + &ss->sig_data->message_hash)); + + /* build json */ + json_t *result; + + result = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("message_hash", + &ss->sig_data->message_hash), + GNUNET_JSON_pack_data_auto ("public_key", + &ss->sig_data->public_key), + GNUNET_JSON_pack_data_auto ("signature_r", + &ss->sig_data->signature.r), + GNUNET_JSON_pack_data_auto ("signature_z", + &ss->sig_data->signature.z) + ); + + /* free all initialized data */ + free_signature_data_struct (ss->sig_data); + + ss->cb (ss->cb_cls, + ss->error_code, + result); +} + + +/** + * Callback to process a POST /sig-share request + * + * @param cls closure + * @param ssd the decoded response body +*/ +static void +signature_share_request_cb (void *cls, + const struct FROSIX_SigShareRequestDetails *ssd) +{ + GNUNET_assert (NULL != cls); + struct FROSIX_SignatureState *ss = cls; + + /* set error code */ + ss->error_code = ssd->ec; + + /* check if this is a valid callback */ + GNUNET_assert (0 < ss->counter); + GNUNET_assert (0 != ssd->http_status); + + /* check if provider index is valid */ + GNUNET_assert (0 < ssd->sig_share.identifier); + GNUNET_assert (255 > ssd->sig_share.identifier); + + struct FROSIX_Provider *fp = &ss->sig_data->providers[ssd->array_index]; + + /* Fill return values in our central struct */ + fp->sig_share.identifier = ssd->sig_share.identifier; + + memcpy (&fp->sig_share.sig_share, + &ssd->sig_share.sig_share, + sizeof (ssd->sig_share.sig_share)); + + memcpy (&fp->sig_share.pk_i, + &ssd->sig_share.pk_i, + sizeof (ssd->sig_share.pk_i)); + + /* call next dkg-commitment request */ + ss->counter--; + if (0 == ss->counter) + { + /* we are the last, check received shares and build final signature */ + check_and_prepare_signature (ss); + } +} + + +/** + * FIXME +*/ +static void +start_signature_shares (struct FROSIX_SignatureState *ss) +{ + ss->sso = GNUNET_malloc (ss->sig_data->threshold * sizeof (char *)); + ss->counter = 0; + + /* build commitment array */ + struct FROST_Commitment commitments[ss->sig_data->threshold]; + for (unsigned int i = 0; i < ss->sig_data->threshold; i++) + { + struct FROSIX_Provider *fp = &ss->sig_data->providers[i]; + + commitments[i].identifier = fp->commitment.identifier; + + FROST_point_copy_to (&commitments[i].hiding_commitment, + &fp->commitment.hiding_commitment); + + FROST_point_copy_to (&commitments[i].binding_commitment, + &fp->commitment.binding_commitment); + } + + for (unsigned int i = 0; i < ss->sig_data->threshold; i++) + { + struct FROSIX_Provider *fp = &ss->sig_data->providers[i]; + + /* hash encryption key */ + struct FROST_HashCode enc_key_hash; + FROSIX_hash_encryption_key (&enc_key_hash, + &fp->enc_key); + + /* compute request id */ + struct FROSIX_SigRequestIdP request_id; + FROSIX_compute_signature_request_id ( + &request_id, + &enc_key_hash, + &ss->sig_data->message_hash); + + ss->sso[i] = FROSIX_sig_share_request ( + FROSIX_REDUX_ctx_, + fp->backend_url, + &request_id, + fp->provider_index, + i, + &fp->enc_key, + &ss->sig_data->message_hash, + commitments, + ss->sig_data->threshold, + &signature_share_request_cb, + ss); + + ss->counter++; + } +} + + + +/** + * Callback to process a POST /sig-commitment request + * + * @param cls closure + * @param scd the decoded response body +*/ +static void +signature_commitment_request_cb (void *cls, + const struct + FROSIX_SigCommitmentRequestDetails *scd) +{ + GNUNET_assert (NULL != cls); + struct FROSIX_SignatureState *ss = cls; + + /* set error code */ + ss->error_code = scd->ec; + + /* check if we have to abort the signing process */ + if (0 == scd->http_status) + { + ss->cb (ss, + ss->error_code, + NULL); + return; + } + + + /* check if this is a valid callback */ + GNUNET_assert (0 < ss->counter); + + /* check if provider index is valid */ + GNUNET_assert (0 < scd->sig_commitment.identifier); + GNUNET_assert (255 > scd->sig_commitment.identifier); + + /* copy commitment in our struct */ + struct FROSIX_Provider *fp = &ss->sig_data->providers[scd->array_index]; + + /* Fill return values in our central struct */ + fp->commitment.identifier = scd->sig_commitment.identifier; + + FROST_point_copy_to (&fp->commitment.hiding_commitment, + &scd->sig_commitment.hiding_commitment); + + FROST_point_copy_to (&fp->commitment.binding_commitment, + &scd->sig_commitment.binding_commitment); + + /* call next dkg-commitment request */ + ss->counter--; + if (0 == ss->counter) + { + /* we are the last, go ahead with sig-share */ + start_signature_shares (ss); + } +} + + +/** + * FIXME +*/ +static void +start_signature_commitments (struct FROSIX_SignatureState *ss) +{ + ss->sco = GNUNET_malloc (ss->sig_data->threshold * sizeof (char *)); + ss->counter = 0; + for (unsigned int i = 0; i < ss->sig_data->threshold; i++) + { + struct FROSIX_Provider *fp = &ss->sig_data->providers[i]; + + /* hash encryption key */ + struct FROST_HashCode enc_key_hash; + FROSIX_hash_encryption_key (&enc_key_hash, + &fp->enc_key); + + /* compute request id */ + struct FROSIX_SigRequestIdP request_id; + FROSIX_compute_signature_request_id ( + &request_id, + &enc_key_hash, + &ss->sig_data->message_hash); + + if (0 == strcmp (fp->auth_method, + "question")) + { + ss->sco[i] = FROSIX_sig_commitment_request ( + FROSIX_REDUX_ctx_, + fp->backend_url, + &request_id, + fp->provider_index, + i, + &enc_key_hash, + NULL, + &fp->auth_pub, + &fp->auth_sig, + fp->auth_method, + &ss->sig_data->message_hash, + &signature_commitment_request_cb, + ss); + } + else + { + ss->sco[i] = FROSIX_sig_commitment_request ( + FROSIX_REDUX_ctx_, + fp->backend_url, + &request_id, + fp->provider_index, + i, + &enc_key_hash, + &fp->auth_data, + NULL, + NULL, + fp->auth_method, + &ss->sig_data->message_hash, + &signature_commitment_request_cb, + ss); + } + + + ss->counter++; + } +} + + +/** + * Helper function to parse a keygen input + * + * @param[in,out] dkg_data A initialized struct + * @param[in] arguments Input from the cli +*/ +enum GNUNET_GenericReturnValue +parse_sign_arguments (struct FROSIX_SignatureData *sig_data, + const json_t *arguments, + json_t *input) +{ + json_t *providers = NULL; + uint8_t max_num = 0; + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_uint8 ("number_of_participants", + &max_num), + GNUNET_JSON_spec_uint8 ("threshold", + &sig_data->threshold), + GNUNET_JSON_spec_fixed_auto ("public_key", + &sig_data->public_key), + GNUNET_JSON_spec_json ("providers", + &providers), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != GNUNET_JSON_parse (arguments, + spec, + NULL, + NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + return GNUNET_NO; + } + + /* get number of providers */ + size_t num_of_providers = json_object_size (input); + + /* validate number of providers */ + GNUNET_assert (sig_data->threshold == num_of_providers); + GNUNET_assert (254 > sig_data->threshold); + GNUNET_assert (0 < sig_data->threshold); + + /* initialize providers */ + sig_data->providers = GNUNET_new_array (sig_data->threshold, + struct FROSIX_Provider); + + uint8_t provider_mapping[sig_data->threshold]; + + /* get involved providers */ + const char *key; + json_t *value; + unsigned int counter = 0; + json_object_foreach (input, + key, + value) + { + /* try to convert key value (string) to unsigned int */ + int key_as_int = atoi (key); + + GNUNET_assert (0 < key_as_int); + GNUNET_assert (254 > key_as_int); + GNUNET_assert (max_num >= key_as_int); + + provider_mapping[counter] = (uint8_t) key_as_int; + counter++; + } + + /* parse provider data */ + for (unsigned int i = 0; i < sig_data->threshold; i++) + { + struct GNUNET_HashCode auth_nonce; + uint8_t provider_index = provider_mapping[i]; + struct GNUNET_JSON_Specification prov_spec[] = { + GNUNET_JSON_spec_uint8 ("provider_index", + &sig_data->providers[i].provider_index), + GNUNET_JSON_spec_string ("backend_url", + (const + char**) &sig_data->providers[i].backend_url), + GNUNET_JSON_spec_fixed_auto ("encryption_key", + &sig_data->providers[i].enc_key), + GNUNET_JSON_spec_string ("auth_method", + &sig_data->providers[i].auth_method), + GNUNET_JSON_spec_fixed_auto ("auth_nonce", + &auth_nonce), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != GNUNET_JSON_parse (json_array_get (providers, + provider_index - 1), + prov_spec, + NULL, + NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (prov_spec); + GNUNET_JSON_parse_free (spec); + return GNUNET_NO; + } + + GNUNET_JSON_parse_free (prov_spec); + + /* convert int index to a string - this is our key */ + char index[5]; + snprintf (index, + 4, + "%d", + sig_data->providers[i].provider_index); + + /* parse challenge solution / answer of security question */ + if (0 == strcmp (sig_data->providers[i].auth_method, + "question")) + { + const char *answer; + + struct GNUNET_JSON_Specification q_spec[] = { + GNUNET_JSON_spec_string (index, + &answer), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != GNUNET_JSON_parse (input, + q_spec, + NULL, + NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (q_spec); + return GNUNET_NO; + } + + GNUNET_JSON_parse_free (q_spec); + + unsigned int amplifier = 1; + /* compute key pair to sign signature */ + struct GNUNET_CRYPTO_Edx25519PrivateKey priv; + struct FROSIX_ChallengeHashP auth_hash; + FROSIX_hash_pow (&auth_hash.hash, + &priv, + &sig_data->providers[i].auth_pub, + &auth_nonce, + answer, + amplifier); + + // Sign data + struct FROSIX_AuthSignaturePS as = { + .purpose.purpose = htonl (72), + .purpose.size = htonl (sizeof (as)), + .mh = sig_data->message_hash, + }; + + GNUNET_CRYPTO_edx25519_sign (&priv, + &as, + &sig_data->providers[i].auth_sig); + } + else + { + /* parse answer as number */ + uint64_t code; + + struct GNUNET_JSON_Specification c_spec[] = { + GNUNET_JSON_spec_uint64 (index, + &code), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != GNUNET_JSON_parse (input, + c_spec, + NULL, + NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (c_spec); + return GNUNET_NO; + } + + GNUNET_JSON_parse_free (c_spec); + + /* compute challenge hash */ + FROSIX_hash_answer (code, + &sig_data->providers[i].auth_data); + } + } + + GNUNET_JSON_parse_free (spec); + + /* check if list of providers is sorted */ + for (unsigned int i = 1; i < sig_data->threshold; i++) + { + GNUNET_assert (sig_data->providers[i].provider_index > + sig_data->providers[i - 1].provider_index); + } + + return GNUNET_OK; +} + + +/** + * +*/ +struct FROSIX_ReduxAction * +FROSIX_redux_sign_start (const json_t *arguments, + json_t *input, + const char *message, + FROSIX_ActionCallback cb, + void *cb_cls) +{ + /* initialize signature data struct */ + struct FROSIX_SignatureData *sig_data = GNUNET_new (struct + FROSIX_SignatureData); + + /* hash message */ + FROST_message_to_hash (&sig_data->message_hash, + message, + strlen (message)); + + /* parse arguments from cli */ + if (GNUNET_OK != parse_sign_arguments (sig_data, + arguments, + input)) + { + free_signature_data_struct (sig_data); + + // FIXME: Return some useful error message + return NULL; + } + + /* lets create a state */ + struct FROSIX_SignatureState *ss = GNUNET_new (struct FROSIX_SignatureState); + ss->cb = cb; + ss->cb_cls = cb_cls; + ss->sig_data = sig_data; + ss->ra.cleanup = &sign_cancel_cb; + ss->ra.cleanup_cls = ss; + + /* get commitments from all parsed providers */ + start_signature_commitments (ss); + + return &ss->ra; +} +\ No newline at end of file diff --git a/src/libfrostdistkeygen/Makefile.am b/src/libfrostdistkeygen/Makefile.am @@ -0,0 +1,19 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/libfrosthigh + +lib_LTLIBRARIES = \ + libfrostdistkeygen.la + +libfrostdistkeygen_la_SOURCES = \ + keygen_common.c keygen_common.h \ + dkg_commitment.c \ + keygen_begin.c \ + validate_params.c \ + keygen_validate_commitment.c \ + keygen_validate_share.c \ + keygen_finalize.c + + libfrostdistkeygen_la_LIBADD = \ + $(top_builddir)/src/libfrostlow/libfrostlow.la \ + $(top_builddir)/src/libfrosthigh/libfrosthigh.la \ + -lgnunetutil diff --git a/src/libfrostdistkeygen/dkg_commitment.c b/src/libfrostdistkeygen/dkg_commitment.c @@ -0,0 +1,60 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file dkg_commitment.c + * @brief helper functions to initialize and free a dkg commitment struct + * @author Joel Urech +*/ +#include "keygen.h" +#include <gnunet/gnunet_util_lib.h> + + +enum GNUNET_GenericReturnValue +FROST_initialize_dkg_commitment (struct FROST_DkgCommitment *dkg_commitment, + uint8_t my_index, + uint8_t threshold) +{ + /* check params */ + if (GNUNET_OK != FROST_validate_dkg_params (my_index, + threshold, + 254)) + return GNUNET_NO; + + /* abort if calling function misbehaves*/ + GNUNET_assert (NULL != dkg_commitment); + + /* init memory and set initial values */ + dkg_commitment->identifier = my_index; + dkg_commitment->share_comm + = GNUNET_malloc (threshold * sizeof (struct FROST_Point)); + + dkg_commitment->shares_commitments_length = threshold; + FROST_scalar_zero (&dkg_commitment->zkp.z); + FROST_point_identity (&dkg_commitment->zkp.r); + + return GNUNET_OK; +} + + +void +FROST_free_dkg_commitment (struct FROST_DkgCommitment dkg_commitments[], + size_t length) +{ + for (unsigned int i = 0; i < length; i++) + { + GNUNET_free (dkg_commitments[i].share_comm); + } +} diff --git a/src/libfrostdistkeygen/keygen_begin.c b/src/libfrostdistkeygen/keygen_begin.c @@ -0,0 +1,100 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file keygen_begin.c + * @brief Implementation of the first round of the distributed key generation + * @author Joel Urech +*/ +#include "keygen.h" +#include "keygen_common.h" + + +enum GNUNET_GenericReturnValue +FROST_keygen_begin (struct FROST_DkgCommitment *dkg_commitment, + struct FROST_DkgShare dkg_shares[], + const struct FROST_DkgContextString *context_string, + const struct FROST_HashCode *additional_data, + uint8_t my_index, + uint8_t num_of_participants, + uint8_t threshold) +{ + /* check params */ + if (GNUNET_OK != FROST_validate_dkg_params (my_index, + threshold, + num_of_participants)) + return GNUNET_NO; + + /* check if calling function misbehaves */ + GNUNET_assert (NULL != dkg_commitment); + GNUNET_assert (NULL != dkg_shares); + GNUNET_assert (NULL != context_string); + + /* derive secret value 'x0' from context_string */ + struct FROST_DkgSecretKey secret; + FROST_kdf_scalar_to_curve (&secret.sk, + 0, + &context_string->con_str); + + /* Generate commitments and shares */ + FROST_generate_shares_ (dkg_shares, + dkg_commitment, + &secret, + &context_string->con_str, + num_of_participants, + threshold); + + /* Generate the signature / zero knowledge proof of secret 'x0' */ + + // hash secret value and map back to a scalar -> our 'rnd'-value + struct FROST_HashState r_h_state; + FROST_hash_init (&r_h_state); + FROST_hash_scalar_update (&r_h_state, + &secret.sk); + FROST_hash_fixed_update (&r_h_state, + "FROST-DKG-ZKP", + strlen ("FROST-DKG-ZKP")); + struct FROST_HashCode r_h; + FROST_hash_final (&r_h_state, + &r_h); + + struct FROST_Scalar r; + FROST_hash_to_scalar (&r, + &r_h); + + // compute signature / zkp + FROST_base_mul_scalar (&dkg_commitment->zkp.r, + &r); + + struct FROST_DkgShareCommitment s_pub; + FROST_base_mul_scalar (&s_pub.sc, + &secret.sk); + + struct FROST_DkgChallenge challenge; + FROST_generate_dkg_challenge_ (&challenge, + my_index, + &s_pub, + &dkg_commitment->zkp, + additional_data); + + FROST_scalar_mul_scalar (&dkg_commitment->zkp.z, + &secret.sk, + &challenge.c); + FROST_scalar_add_scalar (&dkg_commitment->zkp.z, + &dkg_commitment->zkp.z, + &r); + + return GNUNET_OK; +} diff --git a/src/libfrostdistkeygen/keygen_common.c b/src/libfrostdistkeygen/keygen_common.c @@ -0,0 +1,150 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file keygen_common.c + * @brief Implementation of some functions which are used several times in different steps + * of the distributed key generation process. + * @author Joel Urech +*/ +#include "keygen.h" +#include "keygen_common.h" +#include "frost_low.h" + + +/** + * @brief Generates commitments for each of the provided coefficients + * + * @param[out] dkg_commitment The resulting commitment to the polynomial + * @param[in] secret The secret value of the polynomial at coordiante x=0 + * @param[in] coefficients All generated coefficients of the polynomial + * @param[in] coefficients_len Length of array coefficients +*/ +static void +generate_commitments (struct FROST_DkgCommitment *dkg_commitment, + const struct FROST_DkgSecretKey *secret, + const struct FROST_Coefficient coefficients[], + uint8_t coefficients_len) +{ + // Generate commitments + FROST_base_mul_scalar (&dkg_commitment->share_comm[0].sc, + &secret->sk); + + for (int i = 0; i < coefficients_len; i++) + { + FROST_base_mul_scalar (&dkg_commitment->share_comm[i + 1].sc, + &coefficients[i].coeff); + } +} + + +void +FROST_generate_dkg_challenge_ (struct FROST_DkgChallenge *challenge, + uint8_t generator_index, + const struct FROST_DkgShareCommitment *s_pub, + const struct FROST_DkgZkp *zkp, + const struct FROST_HashCode *additional_data) +{ + struct FROST_HashState state; + struct FROST_HashCode hash; + FROST_hash_init (&state); + FROST_hash_uint8_update (&state, + generator_index); + FROST_hash_point_update (&state, + &s_pub->sc); + FROST_hash_point_update (&state, + &zkp->r); + if (NULL != additional_data) /* additional data is optional */ + { + FROST_hash_hash_update (&state, + additional_data); + } + FROST_hash_fixed_update (&state, + "DKG-Challenge", + strlen ("DKG-Challenge")); + FROST_hash_final (&state, + &hash); + FROST_hash_to_scalar (&challenge->c, + &hash); +} + + +void +FROST_generate_shares_ (struct FROST_DkgShare shares[], + struct FROST_DkgCommitment *dkg_commitment, + const struct FROST_DkgSecretKey *secret, + const struct FROST_ShortHashCode *coeff_masterkey, + uint8_t num_of_participants, + uint8_t threshold) +{ + uint8_t numcoeffs = threshold - 1; + + // Sample t-1 participants values + struct FROST_Coefficient coefficients[numcoeffs]; + + for (uint8_t i = 0; i < numcoeffs; i++) + { + if (NULL == coeff_masterkey) + { + FROST_scalar_random (&coefficients[i].coeff); + } + else { + // Derive new subkey + FROST_kdf_scalar_to_curve (&coefficients[i].coeff, + i + 1, /* id '0' is our secret! */ + coeff_masterkey); + } + } + + // Horner's method to evaluate the polynomial at the point x=share_index + // [1 ... n] (i must not be 0) + for (uint8_t i = 1; i <= num_of_participants; i++) + { + struct FROST_Scalar share_index; + struct FROST_Scalar value; + FROST_scalar_set_uint8 (&share_index, + i); + FROST_scalar_zero (&value); + + // ]t-1 ... 0] => [t-2 ... 0] + for (int j = numcoeffs - 1; j >= 0; j--) + { + // Add coeff and multiply with share_index + FROST_scalar_add_scalar (&value, + &value, + &coefficients[j].coeff); + FROST_scalar_mul_scalar (&value, + &value, + &share_index); + } + + // Add secret as the *constant* yi (*x^0) + FROST_scalar_add_scalar (&shares[i - 1].share, + &value, + &secret->sk); + + // set participant identifier + shares[i - 1].identifier = i; + } + + // We have no commitments with trusted dealer + if (NULL != dkg_commitment) + { + generate_commitments (dkg_commitment, + secret, + coefficients, + numcoeffs); + } +} diff --git a/src/libfrostdistkeygen/keygen_common.h b/src/libfrostdistkeygen/keygen_common.h @@ -0,0 +1,96 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file keygen_common.h + * @brief Implementation of some functions which are used several times in + * different steps of the distributed key generation process. + * @author Joel Urech +*/ +#ifndef FROST_KEYGEN_COMMON_H +#define FROST_KEYGEN_COMMON_H + +#include "high_common.h" + +/** + * Struct for the challenge of the dkg zkp +*/ +struct FROST_DkgChallenge +{ + /** + * The challenge is a scalar + */ + struct FROST_Scalar c; +}; + +/** + * Struct for a secret key during a key generation process +*/ +struct FROST_DkgSecretKey +{ + /** + * Our secret key is a scalar + */ + struct FROST_Scalar sk; +}; + +/** + * @brief Generates the challenge of the zero knowledge proof of the secret + * \f$a_{i0}\f$ + * \f$c_i = H(i,"Context-String",g^{a_{i0}},R_i)\f$ + * + * @param[out] challenge The resulting challenge, a scalar in the range of the + * order of the ristretto255-group. + * @param[in] generator_index Index of the participant who has the secret + * \f$a_{i0}\f$ + * @param[in] s_pub The value \f$g^{a_{i0}}\f$ + * @param[in] zkp The value \f$R_i = g^k\f$ where k is a random nonce only + * known to the participant who has the secret \f$a_{i0}\f$ + * @param[in] additional_data If not NULL, this data will be included in the + * challenge of the @a zkp. +*/ +void +FROST_generate_dkg_challenge_ (struct FROST_DkgChallenge *challenge, + uint8_t generator_index, + const struct FROST_DkgShareCommitment *s_pub, + const struct FROST_DkgZkp *zkp, + const struct FROST_HashCode *additional_data); + +/** + * @brief Generates a random threshold-1 degree polynomial and the + * corresponding commitment values. + * + * @param[out] shares Coefficients of the random generated polynomial + * @param[out] dkg_commitment A commitment value for every share + * \f$g^{a_{ij}}\f$, 0 <= j <= threshold-1. + * To use this function in a trusted dealer setup, there are no dkg commitments + * and therefore submit the value NULL. + * @param[in] secret A secret value, which will be added as the constant value + * of the polynomial. + * @param[in] coeff_masterkey Source of high entropy to derive the coefficients + * from and compute the secret polynomial. + * @param num_of_participants How many are participating? + * @param threshold How many participants are required to restore the secret + * (sign a message)? +*/ +void +FROST_generate_shares_ (struct FROST_DkgShare shares[], + struct FROST_DkgCommitment *dkg_commitment, + const struct FROST_DkgSecretKey *secret, + const struct FROST_ShortHashCode *coeff_masterkey, + uint8_t num_of_participants, + uint8_t threshold); + +#endif diff --git a/src/libfrostdistkeygen/keygen_finalize.c b/src/libfrostdistkeygen/keygen_finalize.c @@ -0,0 +1,59 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file keygen_finalize.c + * @brief Implementation of the finalization of the distributed key generation process + * @author Joel Urech +*/ +#include "keygen.h" + +/** + * With the shares of all other participants, this function computes the + * individual key pair and derives the group public key from the commitments. +*/ +void +FROST_keygen_finalize (struct FROST_KeyPair *keypair, + uint8_t my_index, + const struct FROST_DkgShare shares[], + const struct FROST_DkgCommitment commitments[], + uint8_t num_of_participants) +{ + // id + keypair->identifier = my_index; + + // sk_i + FROST_scalar_zero (&keypair->my_sk); + for (int i = 0; i < num_of_participants; i++) + { + FROST_scalar_add_scalar (&keypair->my_sk, + &keypair->my_sk, + &shares[i].share); + } + + // pk_i + FROST_base_mul_scalar (&keypair->my_pk, + &keypair->my_sk); + + // set pk from keypair to 0 + FROST_point_identity (&keypair->group_pk.pk); + + for (int i = 0; i < num_of_participants; i++) + { + FROST_point_add_point (&keypair->group_pk.pk, + &keypair->group_pk.pk, + &commitments[i].share_comm[0].sc); + } +} diff --git a/src/libfrostdistkeygen/keygen_validate_commitment.c b/src/libfrostdistkeygen/keygen_validate_commitment.c @@ -0,0 +1,79 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file keygen_validate_commitment.c + * @brief Implements the validation of the commitments + * @author Joel Urech +*/ +#include "keygen.h" +#include "keygen_common.h" + +/** + * @brief Validates the zero knowledge proof of a commitment. + * + * @param[in] challenge The already calculated challenge for the zkp. + * @param[in] comm A commitment to validate. +*/ +static enum GNUNET_GenericReturnValue +is_valid_zkp (const struct FROST_Scalar *challenge, + const struct FROST_DkgCommitment *comm) +{ + // g^z - (s_pub * challenge) + struct FROST_Point g_z; + FROST_base_mul_scalar (&g_z, &comm->zkp.z); + + struct FROST_Point s_challenge; + FROST_point_mul_scalar (&s_challenge, &comm->share_comm[0].sc, + challenge); + + struct FROST_Point r; + FROST_point_sub_point (&r, &g_z, &s_challenge); + + return FROST_point_cmp (&comm->zkp.r, &r); +} + + +enum GNUNET_GenericReturnValue +FROST_keygen_validate_commitment ( + const struct FROST_DkgCommitment *dkg_commitment, + const struct FROST_HashCode *additional_data, + uint8_t num_of_participants) +{ + /* Check if other party pretends to have an invalid identifier */ + if (0 == dkg_commitment->identifier + || num_of_participants < dkg_commitment->identifier) + return GNUNET_NO; + + /* check every element if it is a valid encoded point */ + if (0 >= dkg_commitment->shares_commitments_length + || dkg_commitment->shares_commitments_length >= 254) + return GNUNET_NO; + for (unsigned int i = 0; i < dkg_commitment->shares_commitments_length; i++) + { + if (GNUNET_OK != FROST_is_valid_point (&dkg_commitment->share_comm[i].sc)) + return GNUNET_NO; + } + + struct FROST_DkgChallenge challenge; + FROST_generate_dkg_challenge_ (&challenge, + dkg_commitment->identifier, + &dkg_commitment-> + share_comm[0], + &dkg_commitment->zkp, + additional_data); + + return is_valid_zkp (&challenge.c, dkg_commitment); +} diff --git a/src/libfrostdistkeygen/keygen_validate_share.c b/src/libfrostdistkeygen/keygen_validate_share.c @@ -0,0 +1,76 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file keygen_validate_share.c + * @brief Implements the validation of a share. + * @author Joel Urech +*/ +#include "keygen.h" +#include "keygen_common.h" + +enum GNUNET_GenericReturnValue +FROST_keygen_validate_share ( + const struct FROST_DkgCommitment *commitment, + const struct FROST_DkgShare *share, + uint8_t my_index) +{ + /* check if share is 0 - we can not multiply the curve generator with 0! */ + { + struct FROST_Scalar zero; + FROST_scalar_zero (&zero); + + if (0 == memcmp (&zero.scalarbytes, + &share->share.scalarbytes, + sizeof (share->share))) + return GNUNET_NO; + } + + /* g^share_i*/ + struct FROST_Point g_secret_share; + FROST_base_mul_scalar (&g_secret_share, + &share->share); + + // initialize com_result + struct FROST_Point com_result; + FROST_point_identity (&com_result); + + // initialize index of receiver + struct FROST_Scalar receiver_index; + FROST_scalar_set_uint8 (&receiver_index, + my_index); + + /* reversed loop over all commitments */ + for (int i = commitment->shares_commitments_length - 1; i >= 0; i--) + { + // com_result += schare_com[i] + FROST_point_add_point (&com_result, + &com_result, + &commitment->share_comm[i].sc); + + // we ignore the multiplication for commitment '0' + if (i != 0) + { + // com_result *= receiver_index + FROST_point_mul_scalar (&com_result, + &com_result, + &receiver_index); + } + } + + /* compare provided and computed points */ + return FROST_point_cmp (&com_result, + &g_secret_share); +} diff --git a/src/libfrostdistkeygen/validate_params.c b/src/libfrostdistkeygen/validate_params.c @@ -0,0 +1,38 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file validate_params.c + * @brief Does a validation of the submitted parameter for the key generation. + * @author Joel Urech +*/ +#include "keygen.h" + +enum GNUNET_GenericReturnValue +FROST_validate_dkg_params (uint8_t identifier, + uint8_t threshold, + uint8_t num_of_participants) +{ + if (identifier <= 0 + || identifier >= 255 + || identifier > num_of_participants + || threshold > num_of_participants + || threshold <= 0 + || threshold >= 254 + || num_of_participants <= 0 + || num_of_participants >= 255) + return GNUNET_NO; + return GNUNET_OK; +} +\ No newline at end of file diff --git a/src/libfrosthigh/Makefile.am b/src/libfrosthigh/Makefile.am @@ -0,0 +1,41 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/libfrostdistkeygen + +lib_LTLIBRARIES = \ + libfrosthigh.la + +libfrosthigh_la_SOURCES = \ + frost_init.c \ + high_common.c high_common.h \ + message_to_hash.c \ + generate_commitment.c \ + validate_commitments.c \ + sign_message_hash.c \ + verify_sig_share.c \ + compose_signature.c + +libfrosthigh_la_LIBADD = \ + $(top_builddir)/src/libfrostlow/libfrostlow.la \ + -lgnunetutil + +# Testcases + +AM_TESTS_ENVIRONMENT=export FROST_PREFIX=$${FROST_PREFIX:-@libdir@};export PATH=$${FROST_PREFIX:-@prefix@}/bin:$$PATH; + +check_PROGRAMS = \ + test_frost + +TESTS = \ + $(check_PROGRAMS) + +test_frost_SOURCES = \ + test_frost.c +test_frost_LDADD = \ + $(top_builddir)/src/libfrostlow/libfrostlow.la \ + $(top_builddir)/src/libfrosthigh/libfrosthigh.la \ + $(top_builddir)/src/libfrostdistkeygen/libfrostdistkeygen.la \ + $(top_builddir)/src/libfrosttrusteddealer/libfrosttrusteddealer.la \ + $(top_builddir)/src/libfrostverify/libfrostverify.la \ + -lsodium \ + -lgnunetutil + +\ No newline at end of file diff --git a/src/libfrosthigh/compose_signature.c b/src/libfrosthigh/compose_signature.c @@ -0,0 +1,58 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file compose_signature.c + * @brief Allows the 'Signatur Aggregator' to aggregate all received signature shares (z-value) + * and together with the commitments, computes the challenge (r-value). + * @author Joel Urech +*/ +#include "frost_high.h" +#include "high_common.h" + +/** + * Aggregates the signature shares from all participants, computes the group commitment aka 'R' value + * and returns the final signature over the given message. + */ +void +FROST_compose_signature (struct FROST_Signature *signature, + const struct FROST_Commitment commitments[], + const struct FROST_SignatureShare signature_shares[], + uint8_t commitments_and_sig_shares_len, + const struct FROST_MessageHash *message_hash) +{ + FROST_scalar_zero (&signature->z); + + for (uint8_t i = 0; i < commitments_and_sig_shares_len; i++) + { + FROST_scalar_add_scalar (&signature->z, &signature->z, + &signature_shares[i].sig_share); + } + + // === Compute the binding factors === + struct FROST_BindingFactor binding_factors[commitments_and_sig_shares_len]; + FROST_compute_binding_factors_ (binding_factors, commitments, + commitments_and_sig_shares_len, + message_hash); + + // Compute the group commitment + struct FROST_GroupCommitment group_commitment; + FROST_compute_group_commitment_ (&group_commitment, commitments, + binding_factors, + commitments_and_sig_shares_len); + + // Copy group_commitment to sig + FROST_point_copy_to (&signature->r, &group_commitment.commitment); +} diff --git a/src/libfrosthigh/frost_init.c b/src/libfrosthigh/frost_init.c @@ -0,0 +1,33 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Frosix + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file frost_init.c + * @brief FROST_init() has always to be called first! It initializes the underlying libsodium library + * @author Joel Urech +*/ +#include "frost_high.h" + +/** + * @brief Initializes the underlying libsodium library. + * Always call this function first, before using libfrost! + * + * @result Returns 0 on success, -1 on failure and 1 if the library had already been initialized +*/ +int +FROST_init () +{ + return FROST_low_init (); +} diff --git a/src/libfrosthigh/generate_commitment.c b/src/libfrosthigh/generate_commitment.c @@ -0,0 +1,65 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Frosix + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file generate_commitment.c + * Derives a nonce and a corresponding commitment from the given message hash + * and the secret key. +*/ +#include "frost_high.h" + + +void +FROST_get_random_seed (struct FROST_CommitmentSeed *seed) +{ + FROST_scalar_random (&seed->scal); +} + + +void +FROST_generate_nonce_and_commitment ( + struct FROST_Nonce *nonce, + struct FROST_Commitment *commitment, + const struct FROST_MessageHash *message_hash, + const struct FROST_CommitmentSeed *seed) +{ + /* get hash of message and secret key, this is our kdf master key */ + struct FROST_ShortHashState shs; + struct FROST_ShortHashCode kdf_masterkey; + + FROST_short_hash_init (&shs); + FROST_short_hash_update_fixed (&shs, + message_hash, + sizeof (*message_hash)); + FROST_short_hash_update_fixed (&shs, + seed, + sizeof (*seed)); + FROST_short_hash_final (&shs, + &kdf_masterkey); + + /* get nonce values with the kdf master key */ + FROST_kdf_scalar_to_curve (&nonce->hiding_nonce, + 1, + &kdf_masterkey); + FROST_kdf_scalar_to_curve (&nonce->binding_nonce, + 2, + &kdf_masterkey); + + /* get commitment values from the nonce values */ + FROST_base_mul_scalar (&commitment->hiding_commitment, + &nonce->hiding_nonce); + FROST_base_mul_scalar (&commitment->binding_commitment, + &nonce->binding_nonce); +} diff --git a/src/libfrosthigh/high_common.c b/src/libfrosthigh/high_common.c @@ -0,0 +1,252 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file high_common.c + * @brief Implementations of function which are used for different tasks during the signing or key generation process. + * @author Joel Urech +*/ +#include "high_common.h" + +/** + * @brief Returns all participants from the commitment list. + * Pseudo code of this function: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-12.html#name-list-operations + * + * @param participants The resulting list of all participating participants + * @param commitments The commitment list which we got from the 'SA' + * @param commitments_len Length of the commitment list +*/ +static void +participants_from_commitment_list ( + uint8_t participants[], + const struct FROST_Commitment commitments[], + uint8_t commitments_len) +{ + for (uint8_t i = 0; i < commitments_len; i++) + { + participants[i] = commitments[i].identifier; + } +} + +/** + * Computes the set of binding values for all participating participants. + * Pseudo code of this function: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-12.html#name-binding-factors-computation +*/ +void +FROST_compute_binding_factors_ ( + struct FROST_BindingFactor binding_factors[], + const struct FROST_Commitment commitments[], + uint8_t commitments_len, + const struct FROST_MessageHash *mh) +{ + // H(group_commitment_list) + struct FROST_HashState hash_state; + FROST_hash_init (&hash_state); + + for (uint8_t i = 0; i < commitments_len; i++) + { + FROST_hash_uint8_update (&hash_state, commitments[i].identifier); + FROST_hash_point_update (&hash_state, + &commitments[i].hiding_commitment); + FROST_hash_point_update (&hash_state, + &commitments[i].binding_commitment); + } + + struct FROST_HashCode group_commitments_hash; + FROST_hash_final (&hash_state, &group_commitments_hash); + + // 2. H(identifier || message || group_commitment_hash) + for (uint8_t i = 0; i < commitments_len; i++) + { + struct FROST_HashState state; + FROST_hash_init (&state); + + FROST_hash_uint8_update (&state, commitments[i].identifier); + FROST_hash_hash_update (&state, &mh->hash); + FROST_hash_hash_update (&state, &group_commitments_hash); + + struct FROST_HashCode rho_input; + FROST_hash_final (&state, &rho_input); + + FROST_hash_to_scalar (&binding_factors[i].binding_factor, &rho_input); + + // Set index + binding_factors[i].identifier = commitments[i].identifier; + } +} + +/** + * Returns the binding factor of a specific participant. + * Pseudo code of this function: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-12.html#name-list-operations +*/ +enum GNUNET_GenericReturnValue +FROST_binding_factor_for_participant_ ( + struct FROST_BindingFactor *binding_factor, + const struct FROST_BindingFactor binding_factors[], + uint8_t binding_factors_len, + uint8_t participant) +{ + for (uint8_t i = 0; i < binding_factors_len; i++) + { + if (participant == binding_factors[i].identifier) + { + FROST_scalar_copy_to (&binding_factor->binding_factor, + &binding_factors[i].binding_factor); + binding_factor->identifier = binding_factors[i].identifier; + return GNUNET_OK; + } + } + return GNUNET_NO; // invalid participant +} + +/** + * Computes the group commitment. + * Pseudo code of this function: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-12.html#name-group-commitment-computatio + * +*/ +void +FROST_compute_group_commitment_ ( + struct FROST_GroupCommitment *group_commitment, + const struct FROST_Commitment commitments[], + const struct FROST_BindingFactor + binding_factors[], + uint8_t comm_and_bind_len) +{ + // Set group commitment to the identity element + FROST_point_identity (&group_commitment->commitment); + + for (uint8_t i = 0; i < comm_and_bind_len; i++) + { + // Get binding factor + struct FROST_BindingFactor binding_factor; + FROST_binding_factor_for_participant_ (&binding_factor, binding_factors, + comm_and_bind_len, + binding_factors[i].identifier); + + // scalarmult binding_nonce_commitment, binding_factor + struct FROST_Point binding_nonce; + FROST_point_mul_scalar (&binding_nonce, + &commitments[i].binding_commitment, + &binding_factor.binding_factor); + + // Point add hiding_nonce_commitment with binding_nonce + struct FROST_Point hiding_nonce; + FROST_point_add_point (&hiding_nonce, &commitments[i].hiding_commitment, + &binding_nonce); + + // Point add group_commitment, ^ + FROST_point_add_point (&group_commitment->commitment, + &group_commitment->commitment, &hiding_nonce); + } +} + +/** + * Computes the lagrange coefficient for a specific participant. + * Pseudo code of this function: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-12.html#name-polynomials + * +*/ +enum GNUNET_GenericReturnValue +FROST_compute_lagrange_coefficient_ ( + struct FROST_Coefficient *coefficient, + uint8_t participant, + const struct FROST_Commitment commitments[], + size_t commitments_len) +{ + uint8_t indices[commitments_len]; + participants_from_commitment_list (indices, commitments, commitments_len); + + // validate inputs -> invalid parameters + if (0 == participant) // own id is NOT 0 + return GNUNET_NO; + + int id_in_indices = 0; + + for (uint8_t i = 0; i < commitments_len; i++) + { + if (0 == indices[i]) // no other id is 0 + return GNUNET_NO; + + if (participant == indices[i]) + id_in_indices++; + } + + if (1 != id_in_indices) // own id exists exactly 1 time + return GNUNET_NO; + + // x-coordinate (id) as 32-byte unsigned char array + struct FROST_Scalar xi; + FROST_scalar_set_uint8 (&xi, participant); + + // Initialize numerator and denominator to '1' and as 32-byte unsigned char + // array + struct FROST_Scalar num; + struct FROST_Scalar den; + FROST_scalar_one (&num); + FROST_scalar_one (&den); + + // Coefficient = num / den = prod(j - 0) / prod(j - i) \ j = i + for (uint8_t j = 0; j < commitments_len; j++) + { + + // If j == i, do nothing! + if (indices[j] != participant) + { + // x-coordinate of 'j' as 32-byte unsigned char array + struct FROST_Scalar xj; + FROST_scalar_set_uint8 (&xj, indices[j]); + + // num *= (j - 0) = j + FROST_scalar_mul_scalar (&num, &num, &xj); + + // den *= (j - i) + struct FROST_Scalar den_temp; + FROST_scalar_sub_scalar (&den_temp, &xj, &xi); + FROST_scalar_mul_scalar (&den, &den, &den_temp); + } + } + + // coeff = num / den = num * inv(den) + struct FROST_Scalar den_inv; + FROST_scalar_invert (&den_inv, &den); + FROST_scalar_mul_scalar (&coefficient->coeff, &num, &den_inv); + + return GNUNET_OK; +} + +/** + * Computes the signature challenge + * Pseudo code of this function: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-12.html#name-signature-challenge-computa +*/ +void +FROST_compute_challenge_ ( + struct FROST_Challenge *challenge, + const struct FROST_GroupCommitment *group_commitment, + const struct FROST_PublicKey *group_pk, + const struct FROST_MessageHash *mh) +{ + struct FROST_HashState hash_state; + FROST_hash_init (&hash_state); + + FROST_hash_point_update (&hash_state, &group_commitment->commitment); + FROST_hash_point_update (&hash_state, &group_pk->pk); + FROST_hash_hash_update (&hash_state, &mh->hash); + + struct FROST_HashCode challenge_hash; + FROST_hash_final (&hash_state, &challenge_hash); + + FROST_hash_to_scalar (&challenge->challenge, &challenge_hash); + + return; +} diff --git a/src/libfrosthigh/high_common.h b/src/libfrosthigh/high_common.h @@ -0,0 +1,150 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Frosix + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file high_common.h + * @brief Provides functions which are used for different tasks during the signing or key generation process. + * @author Joel Urech +*/ +#ifndef FROST_HIGH_COMMON_H +#define FROST_HIGH_COMMON_H + +#include "frost_high.h" + +/** + * Struct for a binding factor +*/ +struct FROST_BindingFactor +{ + /** + * For which participant is this binding factor? + */ + uint8_t identifier; + /** + * The binding factor + */ + struct FROST_Scalar binding_factor; +}; + +/** + * Struct for a group commitment +*/ +struct FROST_GroupCommitment +{ + /** + * Our group commitment is a point on the curve + */ + struct FROST_Point commitment; +}; + +/** + * Struct for the lagrange coefficient +*/ +struct FROST_Coefficient +{ + /** + * Our lagrange coefficient is a FROST_Scalar + */ + struct FROST_Scalar coeff; +}; + +/** + * Struct for the signature challenge +*/ +struct FROST_Challenge +{ + /** + * Our challenge is a hash, mapped to a scalar in range of the order of the ristretto255 group + */ + struct FROST_Scalar challenge; +}; + +/** + * @brief Computes the set of binding values for all participating participants. + * + * @param[out] binding_factors The resulting set of binding factors + * @param[in] commitments Array of all commitments + * @param commitments_len Length of commitments array + * @param[in] mh The message we have to sign + */ +void +FROST_compute_binding_factors_ ( + struct FROST_BindingFactor binding_factors[], + const struct FROST_Commitment commitments[], + uint8_t commitments_len, + const struct FROST_MessageHash *mh); + +/** + * @brief Computes the group commitment. + * + * @param[out] group_commitment The resulting group commitment + * @param[in] commitments List of all commitments + * @param[in] binding_factors Set of all binding factors + * @param comm_and_bind_len Number of elements in commitments and binding_factors + */ +void FROST_compute_group_commitment_ ( + struct FROST_GroupCommitment *group_commitment, + const struct FROST_Commitment commitments[], + const struct FROST_BindingFactor binding_factors[], + uint8_t comm_and_bind_len); + +/** + * @brief Returns the binding factor of a specific participant. + * + * @param[out] binding_factor The found binding factor + * @param[in] binding_factors Set of all binding factors + * @param binding_factors_len Number of elements in binding_factors + * @param participant The participant for whom we are looking for the binding factor + * @return GNUNET_OK if a binding factor was found, otherwise GNUNET_NO +*/ +enum GNUNET_GenericReturnValue +FROST_binding_factor_for_participant_ ( + struct FROST_BindingFactor *binding_factor, + const struct FROST_BindingFactor binding_factors[], + uint8_t binding_factors_len, + uint8_t participant); + +/** + * @brief Computes the lagrange coefficient for a specific participant. + * + * @param[out] coefficient The resulting lagrange coefficient + * @param[in] participant The participant for which we need the lagrange coefficient + * @param[in] commitments List of all commitments. We only need the identifiers of the participants from it + * @param commitments_len Length of commitment list + * @return 1 if success, otherwise 0 +*/ +enum GNUNET_GenericReturnValue +FROST_compute_lagrange_coefficient_ ( + struct FROST_Coefficient *coefficient, + uint8_t participant, + const struct FROST_Commitment commitments[], + size_t commitments_len); + +/** + * @brief Computes the signature challenge + * + * @param[out] challenge The resulting challenge + * @param[in] group_commitment A previously computed group commitment + * @param[in] group_pk Public key of the signing group + * @param[in] mh Our hash of the message we have to sign +*/ +void +FROST_compute_challenge_ ( + struct FROST_Challenge *challenge, + const struct FROST_GroupCommitment *group_commitment, + const struct FROST_PublicKey *group_pk, + const struct FROST_MessageHash *mh); + +#endif diff --git a/src/libfrosthigh/message_to_hash.c b/src/libfrosthigh/message_to_hash.c @@ -0,0 +1,37 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Frosix + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file message_to_hash.c + * @brief Implements a simple hashing function to convert some input bytes into a hash. + * @author Joel Urech +*/ +#include "frost_high.h" + +/** + * We expect our message to be a hash value. This function provides an interface to hash abritrary messages. +*/ +void +FROST_message_to_hash ( + struct FROST_MessageHash *message_hash, + const void *msg, + size_t msg_len) +{ + struct FROST_HashState state; + FROST_hash_init (&state); + FROST_hash_fixed_update (&state, msg, msg_len); + + FROST_hash_final (&state, &message_hash->hash); +} diff --git a/src/libfrosthigh/sign_message_hash.c b/src/libfrosthigh/sign_message_hash.c @@ -0,0 +1,125 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Frosix + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file sign_message_hash.c + * @brief Implements the signing of a message + * @author Joel Urech +*/ +#include <gnunet/gnunet_util_lib.h> +#include "frost_high.h" +#include "high_common.h" + +/** + * @brief Internal function to compute the signature share + * + * @param sig_share The resulting signature share + * @param my_key_pair Secret key material + * @param nonce The generated nonce from round1 + * @param binding_factors Binding factors of all participating participants + * @param binding_factors_len Length of the binding factors array + * @param coefficient Our lagrange coefficient + * @param challenge The group challenge + * @return #GNUNET_OK + * #GNUNET_NO +*/ +static enum GNUNET_GenericReturnValue +compute_sig_share ( + struct FROST_SignatureShare *sig_share, + const struct FROST_KeyPair *my_key_pair, + const struct FROST_Nonce *nonce, + const struct FROST_BindingFactor binding_factors[], + size_t binding_factors_len, + const struct FROST_Coefficient *coefficient, + const struct FROST_Challenge *challenge) +{ + // get my_binding_factor + struct FROST_BindingFactor my_binding_factor; + if (GNUNET_OK + != FROST_binding_factor_for_participant_ (&my_binding_factor, + binding_factors, + binding_factors_len, + my_key_pair->identifier)) + return GNUNET_NO; + + + // binding_nonce * binding_factor + struct FROST_Scalar binding; + FROST_scalar_mul_scalar (&binding, &nonce->binding_nonce, + &my_binding_factor.binding_factor); + + // lambda_i * sk_i * challenge + struct FROST_Scalar challenge_sk; + + FROST_scalar_mul_scalar (&challenge_sk, &coefficient->coeff, + &my_key_pair->my_sk); + FROST_scalar_mul_scalar (&challenge_sk, &challenge_sk, + &challenge->challenge); + + // hiding + binding + FROST_scalar_add_scalar (&sig_share->sig_share, &nonce->hiding_nonce, + &binding); + + // + challenge + FROST_scalar_add_scalar (&sig_share->sig_share, &sig_share->sig_share, + &challenge_sk); + + // Set index + sig_share->identifier = my_key_pair->identifier; + + // Set pk of sk_share + FROST_base_mul_scalar (&sig_share->pk_i, &my_key_pair->my_sk); + + return GNUNET_OK; +} + + +enum GNUNET_GenericReturnValue +FROST_sign_message_hash (struct FROST_SignatureShare *signature_share, + const struct FROST_MessageHash *message_hash, + const struct FROST_Commitment commitments[], + size_t commitments_len, + const struct FROST_KeyPair *my_key_pair, + const struct FROST_Nonce *my_nonce) +{ + // Compute the binding factor(s) + struct FROST_BindingFactor binding_factors[commitments_len]; + FROST_compute_binding_factors_ (binding_factors, commitments, + commitments_len, message_hash); + + // Compute the group commitment + struct FROST_GroupCommitment group_commitment; + FROST_compute_group_commitment_ (&group_commitment, commitments, + binding_factors, commitments_len); + + // Compute the per-message challenge + struct FROST_Challenge challenge; + FROST_compute_challenge_ (&challenge, &group_commitment, + &my_key_pair->group_pk, message_hash); + + // Compute coefficient + struct FROST_Coefficient coeff_i; + + if (GNUNET_OK != FROST_compute_lagrange_coefficient_ (&coeff_i, + my_key_pair->identifier, + commitments, + commitments_len)) + return GNUNET_NO; + + // Compute the signature share + return compute_sig_share (signature_share, my_key_pair, my_nonce, + binding_factors, commitments_len, &coeff_i, + &challenge); +} diff --git a/src/libfrosthigh/test_frost.c b/src/libfrosthigh/test_frost.c @@ -0,0 +1,264 @@ +#include <stdio.h> +#include <string.h> +#include "frost_high.h" +#include "keygen.h" +#include "frost_verify.h" +#include <time.h> +#include <gnunet/gnunet_util_lib.h> + +static void +distributed_key_generation (struct FROST_KeyPair key_pairs[], + const struct FROST_DkgContextString *context_string, + uint8_t num_of_participants, + uint8_t threshold) +{ + /* === Create shares and commitments === */ + struct FROST_DkgCommitment dkg_commitments[num_of_participants]; + struct FROST_DkgShare dkg_shares[num_of_participants][num_of_participants]; + + for (int i = 0; i < num_of_participants; i++) + { + uint8_t my_index = i + 1; + FROST_initialize_dkg_commitment (&dkg_commitments[i], my_index, + threshold); + + + + FROST_keygen_begin (&dkg_commitments[i], + (struct FROST_DkgShare *) &dkg_shares[i], + context_string, + NULL, + my_index, + num_of_participants, + threshold); + } + + /* === Send commitments === */ + + /* === Verify commitments received === */ + for (int i = 0; i < num_of_participants; i++) + { + GNUNET_assert (1 == FROST_keygen_validate_commitment ( + &dkg_commitments[i], + NULL, + num_of_participants)); + } + + + /* === Send shares === */ + /* === Receive shares === */ + + /* === Compute my key share === */ + for (int i = 0; i < num_of_participants; i++) + { + uint8_t my_index = i + 1; // receivers-index + + // Rearrange shares + struct FROST_DkgShare sorted_shares[num_of_participants]; + for (int j = 0; j < num_of_participants; j++) + { + if (j != my_index - 1) + { + // Verify received share against commitments + GNUNET_assert (FROST_keygen_validate_share (&dkg_commitments[j], + &dkg_shares[j][i], + my_index)); + } + + FROST_scalar_copy_to (&sorted_shares[j].share, + &dkg_shares[j][i].share); + sorted_shares[j].identifier = i + 1; + } + + FROST_keygen_finalize (&key_pairs[i], my_index, sorted_shares, + dkg_commitments, num_of_participants); + } + + // Free dkg commitments + FROST_free_dkg_commitment (dkg_commitments, + num_of_participants); +} + + +static int +get_my_key_pair (const struct FROST_KeyPair shares[], + uint8_t id, + uint8_t n) +{ + for (int i = 0; i < n; i++) + { + if (id == shares[i].identifier) + { + return i; + } + } + return -1; +} + +// https://www.tutorialspoint.com/c_standard_library/c_function_qsort.htm +static int +cmp_int (const void *a, const void *b) +{ + return (*(uint8_t*) a - *(uint8_t*) b); +} + + +/* + */ +static void +get_rnd_participants (uint8_t participants[], + uint8_t t, + uint8_t n) +{ + GNUNET_assert (n >= t); + + memset (participants, 0, t * sizeof (uint8_t)); + for (int i = 0; i < t; i++) + { + int check = 1; + while (check != 0) + { + check = 0; + uint32_t x = randombytes_random () % n + 1; + + for (int j = 0; j < t; j++) + { + if (x == participants[j] || x == 0) + { + check = 1; + } + } + if (0 == check) + { + uint8_t y = (uint8_t) x; + participants[i] = y; + } + } + } + + qsort (participants, t, sizeof (uint8_t), cmp_int); +} + + +int +main (void) +{ + GNUNET_log_setup ("WARNING", + NULL, + NULL); + // Init crypto library + if (0 != FROST_init ()) + return 1; + + // ToDo: what if t is '0' + uint8_t t = 7; + uint8_t n = 19; + + // === Generate shares and public key === + struct FROST_KeyPair key_pairs[n]; + + struct FROST_Scalar rnd; + FROST_scalar_random (&rnd); + + struct FROST_ShortHashState state; + FROST_short_hash_init (&state); + FROST_short_hash_update_fixed (&state, + &rnd, + sizeof (rnd)); + + struct FROST_DkgContextString context_string; + FROST_short_hash_final (&state, + &context_string.con_str); + + // FROST_trusted_dealer_keygen (key_pairs, n, t); + distributed_key_generation (key_pairs, &context_string, n, t); + + + // === SA: Get a message === + char input[] = "This is a very important message!!!"; + + struct FROST_MessageHash mh; + FROST_message_to_hash (&mh, input, strlen (input)); + + + // === SA: Choose participants === + // ToDo: Better solution for choosing rnd participants? + uint8_t participants[t]; + get_rnd_participants (participants, t, n); + + + // === Round One / Preprocess - All: Generate nonces and commitments === + struct FROST_Commitment commitment_list[t]; + struct FROST_Nonce nonces[t]; + for (uint8_t i = 0; i < t; i++) + { + int index = get_my_key_pair (key_pairs, participants[i], n); + + struct FROST_CommitmentSeed seed; + FROST_get_random_seed (&seed); + + FROST_generate_nonce_and_commitment (&nonces[i], + &commitment_list[i], + &mh, + &seed); + + commitment_list[i].identifier = key_pairs[index].identifier; + } + + // SA prepares the commitments and sends them to all participants, together + // with the message + // FROST_send_to_participant + + // SA prepares to collect all shares + struct FROST_SignatureShare sig_shares[t]; + + + // === Round Two / Sign - ALL: === + for (uint8_t i = 0; i < t; i++) + { + int index = get_my_key_pair (key_pairs, participants[i], n); + + // Validate all commitments, received from SA + for (uint8_t j = 0; j < t; j++) + { + GNUNET_assert (FROST_validate_commitment (&commitment_list[j])); + } + + + // Sign message + GNUNET_assert (FROST_sign_message_hash (&sig_shares[i], + &mh, + commitment_list, + t, + &key_pairs[index], + &nonces[i])); + + // Send sig_share to SA + } + + + // === SA: verify all signature shares === + for (uint8_t i = 0; i < t; i++) + { + GNUNET_assert (FROST_verify_signature_share (&commitment_list[i], + &sig_shares[i], + commitment_list, t, + &key_pairs[i].group_pk, + &mh)); + } + + // === SA: aggregate all sig shares and computes final signature === + struct FROST_Signature sig; + FROST_compose_signature (&sig, commitment_list, sig_shares, t, &mh); + + + // === SA: publish sig === + + // === Verify signature === + if (GNUNET_OK == FROST_verify_signature (&key_pairs[0].group_pk, + &sig, + &mh)) + return 0; + + return 1; +} diff --git a/src/libfrosthigh/validate_commitments.c b/src/libfrosthigh/validate_commitments.c @@ -0,0 +1,35 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Frosix + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file validate_commitments.c + * @brief Implements the validation of the commitments + * @author Joel Urech +*/ +#include "frost_high.h" + +/** + * Checks, if a commitment consists out of two valid ristretto255-encoded elements. +*/ +enum GNUNET_GenericReturnValue +FROST_validate_commitment ( + const struct FROST_Commitment *commitment) +{ + if (GNUNET_OK != FROST_is_valid_point (&commitment->hiding_commitment) + || GNUNET_OK != FROST_is_valid_point (&commitment->binding_commitment)) + return GNUNET_NO; + + return GNUNET_OK; +} diff --git a/src/libfrosthigh/verify_sig_share.c b/src/libfrosthigh/verify_sig_share.c @@ -0,0 +1,88 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Frosix + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file verify_sig_share.c + * @brief Implements the function to verify a signature share against a commitment + * @author Joel Urech +*/ +#include "frost_high.h" +#include "high_common.h" + +/** + * Gives the 'SA' the possibility to verify each received signature share against the commitment from round1. +*/ +enum GNUNET_GenericReturnValue +FROST_verify_signature_share ( + const struct FROST_Commitment *commitment_i, + const struct FROST_SignatureShare *signature_share_i, + const struct FROST_Commitment commitments[], + uint8_t commitments_len, + const struct FROST_PublicKey *public_key, + const struct FROST_MessageHash *message_hash) +{ + // === Compute the binding factors === + struct FROST_BindingFactor binding_factors[commitments_len]; + FROST_compute_binding_factors_ (binding_factors, commitments, + commitments_len, message_hash); + + struct FROST_BindingFactor binding_factor; + if (0 + == FROST_binding_factor_for_participant_ (&binding_factor, + binding_factors, + commitments_len, + commitment_i->identifier)) + return GNUNET_NO; + + // === Compute the group commitment === + struct FROST_GroupCommitment group_commitment; + FROST_compute_group_commitment_ (&group_commitment, commitments, + binding_factors, commitments_len); + + // === compute the commitment share + struct FROST_Point comm_share; + FROST_point_mul_scalar (&comm_share, &commitment_i->binding_commitment, + &binding_factor.binding_factor); + FROST_point_add_point (&comm_share, &comm_share, + &commitment_i->hiding_commitment); + + // === Compute challenge === + struct FROST_Challenge challenge; + FROST_compute_challenge_ (&challenge, &group_commitment, public_key, + message_hash); + + // === Compute coefficient + struct FROST_Coefficient coeff; + if (GNUNET_OK + != FROST_compute_lagrange_coefficient_ (&coeff, + commitment_i->identifier, + commitments, commitments_len)) + return GNUNET_NO; + + // Compute relation values + struct FROST_Point l; + FROST_base_mul_scalar (&l, &signature_share_i->sig_share); + + struct FROST_Scalar challenge_lambda; + FROST_scalar_mul_scalar (&challenge_lambda, &challenge.challenge, + &coeff.coeff); + + struct FROST_Point r; + FROST_point_mul_scalar (&r, &signature_share_i->pk_i, &challenge_lambda); + FROST_point_add_point (&r, &r, &comm_share); + + return FROST_point_cmp (&l, + &r); +} diff --git a/src/libfrostlow/Makefile.am b/src/libfrostlow/Makefile.am @@ -0,0 +1,12 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +lib_LTLIBRARIES = \ + libfrostlow.la + +libfrostlow_la_SOURCES = \ + frost_low.c + +libfrostlow_la_LIBADD = \ + -lsodium \ + -lgnunetutil diff --git a/src/libfrostlow/frost_low.c b/src/libfrostlow/frost_low.c @@ -0,0 +1,378 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file frost_low.c + * @brief Wrapper of all used functions from the crypto library libsodium + * @author Joel Urech +*/ +#include <string.h> +#include <gnunet/gnunet_util_lib.h> +#include "frost_low.h" + +int +FROST_low_init () +{ + return sodium_init (); +} + + +// Points +void +FROST_point_mul_scalar (struct FROST_Point *result, + const struct FROST_Point *pt, + const struct FROST_Scalar *scal) +{ + GNUNET_assert (0 == crypto_scalarmult_ristretto255 (result->xcoord, + scal->scalarbytes, + pt->xcoord)); +} + + +void +FROST_point_add_point (struct FROST_Point *result, + const struct FROST_Point *p, + const struct FROST_Point *q) +{ + GNUNET_assert (0 == crypto_core_ristretto255_add (result->xcoord, + p->xcoord, + q->xcoord)); +} + + +void +FROST_point_sub_point (struct FROST_Point *result, + const struct FROST_Point *p, + const struct FROST_Point *q) +{ + GNUNET_assert (0 == crypto_core_ristretto255_sub (result->xcoord, + p->xcoord, + q->xcoord)); +} + + +void +FROST_point_identity (struct FROST_Point *result) +{ + memset (result->xcoord, + 0, + sizeof (*result)); +} + + +void +FROST_base_mul_scalar (struct FROST_Point *result, + const struct FROST_Scalar *scal) +{ + GNUNET_assert (0 == crypto_scalarmult_ristretto255_base (result->xcoord, + scal->scalarbytes)); +} + + +void +FROST_scalar_add_scalar (struct FROST_Scalar *result, + const struct FROST_Scalar *xscal, + const struct FROST_Scalar *yscal) +{ + crypto_core_ristretto255_scalar_add (result->scalarbytes, + xscal->scalarbytes, + yscal->scalarbytes); +} + + +void +FROST_scalar_mul_scalar (struct FROST_Scalar *result, + const struct FROST_Scalar *xscal, + const struct FROST_Scalar *yscal) +{ + crypto_core_ristretto255_scalar_mul (result->scalarbytes, + xscal->scalarbytes, + yscal->scalarbytes); +} + + +void +FROST_scalar_sub_scalar (struct FROST_Scalar *result, + const struct FROST_Scalar *xscal, + const struct FROST_Scalar *yscal) +{ + crypto_core_ristretto255_scalar_sub (result->scalarbytes, + xscal->scalarbytes, + yscal->scalarbytes); +} + + +void +FROST_scalar_invert (struct FROST_Scalar *result, + const struct FROST_Scalar *scal) +{ + GNUNET_assert (0 == crypto_core_ristretto255_scalar_invert ( + result->scalarbytes, + scal->scalarbytes)); +} + + +void +FROST_point_random (struct FROST_Point *result) +{ + crypto_core_ristretto255_random (result->xcoord); +} + + +void +FROST_scalar_random (struct FROST_Scalar *result) +{ + crypto_core_ristretto255_scalar_random (result->scalarbytes); +} + + +void +FROST_hash_init (struct FROST_HashState *state) +{ + GNUNET_assert (0 == crypto_hash_sha512_init (&state->state)); +} + + +void +FROST_hash_fixed_update (struct FROST_HashState *state, + const void *msg, + size_t len) +{ + GNUNET_assert (0 == crypto_hash_sha512_update (&state->state, + msg, + len)); +} + + +void +FROST_hash_point_update (struct FROST_HashState *state, + const struct FROST_Point *pt) +{ + GNUNET_assert (0 == crypto_hash_sha512_update (&state->state, + pt->xcoord, + sizeof (*pt))); +} + + +void +FROST_hash_hash_update (struct FROST_HashState *state, + const struct FROST_HashCode *hash) +{ + GNUNET_assert (0 == crypto_hash_sha512_update (&state->state, + hash->hashbytes, + sizeof (*hash))); +} + + +void +FROST_hash_scalar_update (struct FROST_HashState *state, + const struct FROST_Scalar *scal) +{ + GNUNET_assert (0 == crypto_hash_sha512_update (&state->state, + scal->scalarbytes, + sizeof (*scal))); +} + + +void +FROST_hash_uint8_update (struct FROST_HashState *state, + uint8_t identifier) +{ + GNUNET_assert (0 == crypto_hash_sha512_update (&state->state, + &identifier, + sizeof (identifier))); +} + + +void +FROST_hash_final (struct FROST_HashState *state, + struct FROST_HashCode *result) +{ + GNUNET_assert (0 == crypto_hash_sha512_final (&state->state, + result->hashbytes)); +} + + +void +FROST_hash_to_curve (struct FROST_Point *result, + const struct FROST_HashCode *hash) +{ + GNUNET_assert (0 == crypto_core_ristretto255_from_hash (result->xcoord, + hash->hashbytes)); +} + + +enum GNUNET_GenericReturnValue +FROST_hash_cmp (const struct FROST_HashCode *first, + const struct FROST_HashCode *second) +{ + if (0 == memcmp (&first->hashbytes, + &second->hashbytes, + sizeof (*first))) + return GNUNET_OK; + return GNUNET_NO; +} + + +void +FROST_hash_to_scalar (struct FROST_Scalar *result, + const struct FROST_HashCode *hash) +{ + crypto_core_ristretto255_scalar_reduce (result->scalarbytes, + hash->hashbytes); +} + + +void +FROST_short_hash_init (struct FROST_ShortHashState *state) +{ + GNUNET_assert (0 == crypto_hash_sha256_init (&state->state)); +} + + +void +FROST_short_hash_update_fixed (struct FROST_ShortHashState *state, + const void *msg, + size_t len) +{ + GNUNET_assert (0 == crypto_hash_sha256_update (&state->state, + msg, + len)); +} + + +void +FROST_short_hash_final (struct FROST_ShortHashState *state, + struct FROST_ShortHashCode *result) +{ + GNUNET_assert (0 == crypto_hash_sha256_final (&state->state, + result->hashbytes)); +} + + +void +FROST_point_copy_to (struct FROST_Point *destination, + const struct FROST_Point *origin) +{ + memcpy (&destination->xcoord, + &origin->xcoord, + sizeof (*destination)); +} + + +void +FROST_scalar_copy_to (struct FROST_Scalar *destination, + const struct FROST_Scalar *origin) +{ + memcpy (&destination->scalarbytes, + &origin->scalarbytes, + sizeof (*destination)); +} + + +void +FROST_scalar_zero (struct FROST_Scalar *scal) +{ + memset (scal->scalarbytes, + 0, + sizeof (*scal)); +} + + +void +FROST_scalar_one (struct FROST_Scalar *scal) +{ + memset (scal->scalarbytes, + 0, + sizeof (*scal)); + uint8_t one = 1; + memcpy (scal->scalarbytes, + &one, + sizeof (one)); +} + + +void +FROST_scalar_set_uint8 (struct FROST_Scalar *result, + uint8_t number) +{ + FROST_scalar_zero (result); + memcpy (result, + &number, + sizeof (number)); +} + + +enum GNUNET_GenericReturnValue +FROST_point_cmp (const struct FROST_Point *p, + const struct FROST_Point *q) +{ + if (0 == memcmp (p, + q, + crypto_core_ristretto255_BYTES)) + return GNUNET_OK; + return GNUNET_NO; +} + + +enum GNUNET_GenericReturnValue +FROST_is_valid_point (const struct FROST_Point *p) +{ + struct FROST_Point identity; + FROST_point_identity (&identity); + + if (1 == crypto_core_ristretto255_is_valid_point (p->xcoord) + && GNUNET_NO == FROST_point_cmp (&identity, + p)) + return GNUNET_OK; + return GNUNET_NO; +} + + +void +FROST_kdf_scalar_to_curve (struct FROST_Scalar *subkey, + uint64_t subkey_id, + const struct FROST_ShortHashCode *masterkey) +{ + struct FROST_HashCode subkey_raw; + GNUNET_assert (0 == crypto_kdf_derive_from_key (subkey_raw.hashbytes, + sizeof (subkey_raw), + subkey_id, + "FROSTLOW", + masterkey->hashbytes)); + + FROST_hash_to_scalar (subkey, + &subkey_raw); +} + + +enum GNUNET_GenericReturnValue +FROST_pow_hash (struct FROST_HashCode *hash, + const char *answer, + size_t length, + const struct FROST_PowSalt *salt, + uint8_t difficulty) +{ + if (0 != crypto_pwhash (hash->hashbytes, + sizeof (*hash), + answer, + length, + salt->bytes, + crypto_pwhash_OPSLIMIT_MODERATE * difficulty, + crypto_pwhash_MEMLIMIT_MODERATE, + crypto_pwhash_ALG_ARGON2ID13)) + return GNUNET_NO; + return GNUNET_OK; +} +\ No newline at end of file diff --git a/src/libfrosttrusteddealer/Makefile.am b/src/libfrosttrusteddealer/Makefile.am @@ -0,0 +1,13 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/libfrostdistkeygen -I$(top_srcdir)/src/libfrosthigh + +lib_LTLIBRARIES = \ + libfrosttrusteddealer.la + +libfrosttrusteddealer_la_SOURCES = \ + trusteddealer.c + +libfrosttrusteddealer_la_LIBADD = \ + $(top_builddir)/src/libfrosthigh/libfrosthigh.la \ + $(top_builddir)/src/libfrostdistkeygen/libfrostdistkeygen.la \ + $(top_builddir)/src/libfrostlow/libfrostlow.la diff --git a/src/libfrosttrusteddealer/trusteddealer.c b/src/libfrosttrusteddealer/trusteddealer.c @@ -0,0 +1,66 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file trusteddealer.c + * @brief Implementation of the trusted dealer key generation + * @author Joel Urech +*/ +#include "frost_high.h" +#include "keygen.h" +#include "keygen_common.h" + +/** + * Generates a rnd key pair + * + * @param[out] sk the complete secret key + * @param[out] pk corresponding public key +*/ +static void +generate_keypair (struct FROST_DkgSecretKey *sk, + struct FROST_PublicKey *pk) +{ + FROST_scalar_random (&sk->sk); + FROST_base_mul_scalar (&pk->pk, &sk->sk); +} + + +void +FROST_trusted_dealer_keygen (struct FROST_KeyPair key_pairs[], + uint8_t num_of_participants, + uint8_t threshold) +{ + // Generate keypair + struct FROST_DkgSecretKey secret_key; + struct FROST_PublicKey public_key; + generate_keypair (&secret_key, &public_key); + + struct FROST_DkgShare participant_shares[num_of_participants]; + FROST_generate_shares_ (participant_shares, + NULL, + &secret_key, + NULL, + num_of_participants, threshold); + + for (int i = 0; i < num_of_participants; i++) + { + key_pairs[i].identifier = i + 1; + FROST_point_copy_to (&key_pairs[i].group_pk.pk, &public_key.pk); + FROST_scalar_copy_to (&key_pairs[i].my_sk, + &participant_shares[i].share); + FROST_base_mul_scalar (&key_pairs[i].my_pk, + &participant_shares[i].share); + } +} diff --git a/src/libfrostverify/Makefile.am b/src/libfrostverify/Makefile.am @@ -0,0 +1,13 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/libfrosthigh + +lib_LTLIBRARIES = \ + libfrostverify.la + +libfrostverify_la_SOURCES = \ + verify_signature.c + +libfrostverify_la_LIBADD = \ + $(top_builddir)/src/libfrosthigh/libfrosthigh.la \ + $(top_builddir)/src/libfrostlow/libfrostlow.la + +\ No newline at end of file diff --git a/src/libfrostverify/verify_signature.c b/src/libfrostverify/verify_signature.c @@ -0,0 +1,55 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Frosix + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file verify_signature.c + * @brief Implementation of the signature verification function + * @author Joel Urech +*/ +#include "high_common.h" + +/** + * Verifies the validity of a given signature and hash of a message against a + * public key. + */ +enum GNUNET_GenericReturnValue +FROST_verify_signature ( + const struct FROST_PublicKey *public_key, + const struct FROST_Signature *signature, + const struct FROST_MessageHash *message_hash) +{ + struct FROST_GroupCommitment sig_r; + FROST_point_copy_to (&sig_r.commitment, &signature->r); + + // compute challenge H(r || pk || m) + struct FROST_Challenge challenge; + FROST_compute_challenge_ (&challenge, &sig_r, public_key, message_hash); + + // pk^challenge + struct FROST_Point pk_challenge; + FROST_point_mul_scalar (&pk_challenge, &public_key->pk, + &challenge.challenge); + + // g^sig + struct FROST_Point g_sig; + FROST_base_mul_scalar (&g_sig, &signature->z); + + // g^sig - pk^challenge + struct FROST_Point ver_r; + FROST_point_sub_point (&ver_r, &g_sig, &pk_challenge); + + return FROST_point_cmp (&signature->r, + &ver_r); +} diff --git a/src/restclient/Makefile.am b/src/restclient/Makefile.am @@ -0,0 +1,30 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/backend + +lib_LTLIBRARIES = \ + libfrosixrest.la + +libfrosixrest_la_SOURCES = \ + frosix_api_config.c \ + frosix_api_seed_get.c \ + frosix_api_curl_defaults.c frosix_api_curl_defaults.h \ + frosix_api_dkg-commitment_request.c \ + frosix_api_dkg-share_request.c \ + frosix_api_dkg-key_store.c \ + frosix_api_auth-challenge_request.c \ + frosix_api_sig-commitment_request.c \ + frosix_api_sig-share_request.c \ + frosix_api_dkg-key_delete.c +libfrosixrest_la_LIBADD = \ + $(top_builddir)/src/libfrostdistkeygen/libfrostdistkeygen.la \ + -lgnunetcurl \ + -lgnunetjson \ + -lgnunetutil \ + -ljansson \ + -ltalerjson \ + -ltalercurl \ + -ltalermerchant \ + -ltalerjson \ + -ltalerutil \ + -lcurl \ + $(XLIB) diff --git a/src/restclient/frosix_api_auth-challenge_request.c b/src/restclient/frosix_api_auth-challenge_request.c @@ -0,0 +1,286 @@ +/* + This file is part of Frosix + Copyright (C) 2014-2019 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2.1, + or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with Frosix; see the file COPYING.LGPL. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file restclient/frosix_api_auth-challenge_request.c + * @brief Implementation of the /auth-challenge POST + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + * @author Joel Urech + */ +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include "frosix_service.h" +#include "frosix_api_curl_defaults.h" +#include <taler/taler_json_lib.h> + +/** + * @brief A Contract Operation Handle + */ +struct FROSIX_ChallengeRequestOperation +{ + /** + * The url for this request, including parameters. + */ + char *url; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * The CURL context to connect to the backend + */ + struct GNUNET_CURL_Context *ctx; + + /** + * Function to call with the result. + */ + FROSIX_ChallengeRequestCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; +}; + + +void +FROSIX_auth_challenge_post_cancel (struct FROSIX_ChallengeRequestOperation *aco) +{ + if (NULL != aco->job) + { + GNUNET_CURL_job_cancel (aco->job); + aco->job = NULL; + } + GNUNET_free (aco->url); + GNUNET_free (aco); +} + + +/** + * Process POST /auth-challenge response + */ +static void +handle_auth_challenge_post_finished (void *cls, + long response_code, + const void *response) +{ + struct FROSIX_ChallengeRequestOperation *aco = cls; + struct FROSIX_ChallengeRequestDetails acd; + const json_t *json_response = response; + + aco->job = NULL; + acd.http_status = response_code; + acd.ec = TALER_EC_NONE; + + switch (response_code) + { + case 0: + /* Hard error */ + GNUNET_break (0); + acd.crs = FROSIX_CRS_HTTP_ERROR; + acd.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + case MHD_HTTP_CREATED: + case MHD_HTTP_OK: + { + acd.crs = FROSIX_CRS_SUCCESS; + acd.response = json_deep_copy (json_response); + break; + } + case MHD_HTTP_BAD_REQUEST: + /* We have a conflict with the API */ + GNUNET_break (0); + acd.crs = FROSIX_CRS_CLIENT_ERROR; + acd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* The provider has a problem! */ + GNUNET_break (0); + acd.crs = FROSIX_CRS_SERVER_ERROR; + acd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + default: + /* Unexpected response code */ + GNUNET_break (0); + acd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + } + + /* return to callback function with the data from the response */ + aco->cb (aco->cb_cls, + &acd); + aco->cb = NULL; + + FROSIX_auth_challenge_post_cancel (aco); + return; +} + + +/** + * Handle HTTP header received by curl. + * + * @param buffer one line of HTTP header data + * @param size size of an item + * @param userdata our `struct FROSIX_SigCommitmentRequestOperation` + * @return `size * nitems` +*/ +static size_t +handle_header (char *buffer, + size_t size, + size_t nitems, + void *userdata) +{ + // struct FROSIX_SigCommitmentRequestOperation *sco = userdata; + size_t total = size * nitems; + char *ndup; + const char *hdr_type; + char *hdr_val; + char *sp; + + ndup = GNUNET_strndup (buffer, + total); + + hdr_type = strtok_r (ndup, + ":", + &sp); + if (NULL == hdr_type) + { + GNUNET_free (ndup); + return total; + } + hdr_val = strtok_r (NULL, + "\n\r", + &sp); + if (NULL == hdr_val) + { + GNUNET_free (ndup); + return total; + } + if (' ' == *hdr_val) + hdr_val++; + /* ... FIXME */ + return total; +} + + +struct FROSIX_ChallengeRequestOperation * +FROSIX_auth_challenge_post ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct FROSIX_ChallengeRequestIdP *uuid, + const struct FROSIX_EncryptionKey *encryption_key, + const char *auth_method, + const char *auth_data, + const struct GNUNET_HashCode *auth_nonce, + const struct FROST_MessageHash *message_hash, + FROSIX_ChallengeRequestCallback cb, + void *cb_cls) +{ + struct FROSIX_ChallengeRequestOperation *aco; + CURL *eh; + char *json_str; + + /* check if we got a callback function, abort if not */ + GNUNET_assert (NULL != cb); + + aco = GNUNET_new (struct FROSIX_ChallengeRequestOperation); + + { + /* prepare URL */ + char *uuid_str; + char *path; + + uuid_str = GNUNET_STRINGS_data_to_string_alloc (uuid, + sizeof (*uuid)); + + GNUNET_asprintf (&path, + "auth-challenge/%s", + uuid_str); + + aco->url = TALER_url_join (backend_url, + path, + NULL); + + GNUNET_free (path); + GNUNET_free (uuid_str); + } + + { + /* pack the json object for the request body */ + json_t *auth_challenge_data; + auth_challenge_data = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("encryption_key", + encryption_key), + GNUNET_JSON_pack_string ("auth_method", + auth_method), + GNUNET_JSON_pack_string ("auth_data", + auth_data), + GNUNET_JSON_pack_data_auto ("auth_nonce", + auth_nonce), + GNUNET_JSON_pack_data_auto ("message_hash", + message_hash)); + + json_str = json_dumps (auth_challenge_data, + JSON_COMPACT); + + /* check if we have a json object, abort if it was not successful */ + GNUNET_assert (NULL != json_str); + + json_decref (auth_challenge_data); + } + + /* prepare curl options and fire the request */ + aco->ctx = ctx; + aco->cb = cb; + aco->cb_cls = cb_cls; + + eh = FROSIX_curl_easy_get_ (aco->url); + + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDS, + json_str)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDSIZE, + strlen (json_str))); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERFUNCTION, + &handle_header)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERDATA, + aco)); + + aco->job = GNUNET_CURL_job_add (ctx, + eh, + &handle_auth_challenge_post_finished, + aco); + + return aco; +} diff --git a/src/restclient/frosix_api_config.c b/src/restclient/frosix_api_config.c @@ -0,0 +1,280 @@ +/* + This file is part of Frosix + Copyright (C) 2020, 2021 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file restclient/frosix_api_config.c + * @brief Implementation of the /config GET + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + */ +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include "frosix_service.h" +#include "frosix_api_curl_defaults.h" +#include <gnunet/gnunet_json_lib.h> +#include <taler/taler_json_lib.h> + + +/** + * Which version of the Taler protocol is implemented + * by this library? Used to determine compatibility. + */ +#define FROSIX_PROTOCOL_CURRENT 0 + +/** + * How many versions are we backwards compatible with? + */ +#define FROSIX_PROTOCOL_AGE 0 + + + +/** + * Function called when we're done processing the + * HTTP /config request. + * + * @param cls the `struct FROSIX_ConfigOperation` + * @param response_code HTTP response code, 0 on error + * @param response parsed JSON result, NULL on error + */ +static void +handle_config_finished (void *cls, + long response_code, + const void *response) +{ + struct FROSIX_ConfigOperation *co = cls; + const json_t *json = response; + + co->job = NULL; + + switch (response_code) + { + case 0: + /* No reply received */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Backend `%s' failed to respond to GET /config\n", + co->url); + break; + case MHD_HTTP_OK: + { + const char *name; + struct FROSIX_Config fcfg; + fcfg.provider_index = co->provider_index; + json_t *methods; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("name", + &name), + GNUNET_JSON_spec_string ("business_name", + &fcfg.business_name), + GNUNET_JSON_spec_string ("version", + &fcfg.version), + GNUNET_JSON_spec_json ("methods", + &methods), + TALER_JSON_spec_amount_any ("annual_fee", + &fcfg.annual_fee), + TALER_JSON_spec_amount_any ("signature_creation_fee", + &fcfg.signature_creation_fee), + TALER_JSON_spec_amount_any ("liability_limit", + &fcfg.liability_limit), + GNUNET_JSON_spec_fixed_auto ("provider_salt", + &fcfg.provider_salt), + GNUNET_JSON_spec_fixed_auto ("public_key", + &fcfg.public_key), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (json, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + json_dumpf (json, + stderr, + JSON_INDENT (2)); + response_code = 0; + break; + } + if (0 != strcmp (name, + "frosix")) + { + GNUNET_JSON_parse_free (spec); + response_code = 0; + break; + } + { + unsigned int age; + unsigned int revision; + unsigned int current; + char dummy; + + if (3 != sscanf (fcfg.version, + "%u:%u:%u%c", + &current, + &revision, + &age, + &dummy)) + { + GNUNET_break_op (0); + response_code = 0; + GNUNET_JSON_parse_free (spec); + break; + } + if ( (FROSIX_PROTOCOL_CURRENT < current) && + (FROSIX_PROTOCOL_CURRENT < current - age) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Provider protocol version too new\n"); + response_code = 0; + GNUNET_JSON_parse_free (spec); + break; + } + if ( (FROSIX_PROTOCOL_CURRENT > current) && + (FROSIX_PROTOCOL_CURRENT - FROSIX_PROTOCOL_AGE > current) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Provider protocol version too old\n"); + GNUNET_break_op (0); + response_code = 0; + GNUNET_JSON_parse_free (spec); + break; + } + } + if (! json_is_array (methods)) + { + GNUNET_break_op (0); + GNUNET_JSON_parse_free (spec); + response_code = 0; + break; + } + fcfg.methods_length = json_array_size (methods); + { + struct FROSIX_AuthorizationMethodConfig mcfg[GNUNET_NZL ( + fcfg.methods_length)]; + + for (unsigned int i = 0; i<fcfg.methods_length; i++) + { + struct FROSIX_AuthorizationMethodConfig *m = &mcfg[i]; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("type", + &m->type), + TALER_JSON_spec_amount_any ("cost", + &m->usage_fee), + GNUNET_JSON_spec_end () + }; + + if ( (GNUNET_OK != + GNUNET_JSON_parse (json_array_get (methods, + i), + spec, + NULL, NULL)) ) + { + GNUNET_break_op (0); + GNUNET_JSON_parse_free (spec); + response_code = 0; + goto end; + } + } + fcfg.methods = mcfg; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Good backend found at `%s'\n", + co->url); + co->cb (co->cb_cls, + MHD_HTTP_OK, + &fcfg); + GNUNET_JSON_parse_free (spec); + FROSIX_config_cancel (co); + return; + } + } + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the anastasis server is buggy + (or API version conflict); just pass JSON reply to the application */ + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify */ + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + (unsigned int) response_code); + GNUNET_break_op (0); + break; + } + end: + co->cb (co->cb_cls, + response_code, + NULL); + FROSIX_config_cancel (co); +} + + +struct FROSIX_ConfigOperation * +FROSIX_get_config (struct GNUNET_CURL_Context *ctx, + const char *base_url, + uint8_t provider_index, + FROSIX_ConfigCallback cb, + void *cb_cls) +{ + struct FROSIX_ConfigOperation *co; + + co = GNUNET_new (struct FROSIX_ConfigOperation); + co->url = TALER_url_join (base_url, + "config", + NULL); + co->provider_index = provider_index; + co->ctx = ctx; + co->cb = cb; + co->cb_cls = cb_cls; + { + CURL *eh; + eh = FROSIX_curl_easy_get_ (co->url); + co->job = GNUNET_CURL_job_add (ctx, + eh, + &handle_config_finished, + co); + } + + if (NULL == co->job) + { + GNUNET_free (co->url); + GNUNET_free (co); + return NULL; + } + + return co; +} + + +void +FROSIX_config_cancel (struct FROSIX_ConfigOperation *co) +{ + if (NULL != co->job) + { + GNUNET_CURL_job_cancel (co->job); + co->job = NULL; + } + GNUNET_free (co->url); + GNUNET_free (co); +} + + +/* end of frosix_api_config.c */ diff --git a/src/restclient/frosix_api_curl_defaults.c b/src/restclient/frosix_api_curl_defaults.c @@ -0,0 +1,58 @@ +/* + This file is part of Frosix + Copyright (C) 2014-2019 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + Frosix; see the file COPYING. If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file restclient/frosix_api_curl_defaults.c + * @brief curl easy handle defaults + * @author Florian Dold + */ +#include "platform.h" +#include "frosix_api_curl_defaults.h" + +CURL * +FROSIX_curl_easy_get_ (const char *url) +{ + CURL *eh; + + eh = curl_easy_init (); + if (NULL == eh) + return NULL; + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + url)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_FOLLOWLOCATION, + 1L)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_TCP_FASTOPEN, + 1L)); + /* limit MAXREDIRS to 5 as a simple security measure against + a potential infinite loop caused by a malicious target */ + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_MAXREDIRS, + 5L)); + /* Enable compression (using whatever curl likes), see + https://curl.se/libcurl/c/CURLOPT_ACCEPT_ENCODING.html */ + GNUNET_break (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_ACCEPT_ENCODING, + "")); + return eh; +} diff --git a/src/restclient/frosix_api_curl_defaults.h b/src/restclient/frosix_api_curl_defaults.h @@ -0,0 +1,38 @@ +/* + This file is part of Frosix + Copyright (C) 2014-2019 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + Frosix; see the file COPYING. If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file restclient/frosix_api_curl_defaults.h + * @brief curl easy handle defaults + * @author Florian Dold + */ + +#ifndef _FROSIX_API_CURL_DEFAULTS_H +#define _FROSIX_API_CURL_DEFAULTS_H + +#include <gnunet/gnunet_curl_lib.h> + + +/** + * Get a curl handle with the right defaults + * for the exchange lib. In the future, we might manage a pool of connections here. + * + * @param url URL to query + */ +CURL * +FROSIX_curl_easy_get_ (const char *url); + +#endif /* _TALER_CURL_DEFAULTS_H */ diff --git a/src/restclient/frosix_api_dkg-commitment_request.c b/src/restclient/frosix_api_dkg-commitment_request.c @@ -0,0 +1,386 @@ +/* + This file is part of ANASTASIS + Copyright (C) 2014-2019 Anastasis SARL + + ANASTASIS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2.1, + or (at your option) any later version. + + ANASTASIS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with ANASTASIS; see the file COPYING.LGPL. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file restclient/frosix_api_dkg-commitment_request.c + * @brief Implementation of the /dkg-commitment POST + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + * @author Joel Urech + */ +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include "frosix_service.h" +#include "frost_high.h" +#include "frosix_api_curl_defaults.h" +#include <gnunet/gnunet_json_lib.h> +#include <taler/taler_json_lib.h> + + +/** + * @brief A commitment request operation handle + */ +struct FROSIX_DkgCommitmentRequestOperation +{ + /** + * The url for this request, including parameters. + */ + char *url; + + /** + * + */ + uint8_t provider_index; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * The CURL context to connect to the backend + */ + struct GNUNET_CURL_Context *ctx; + + /** + * Function to call with the result. + */ + FROSIX_DkgCommitmentRequestCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; +}; + + +void +FROSIX_dkg_commitment_request_cancel ( + struct FROSIX_DkgCommitmentRequestOperation *dco) +{ + if (NULL != dco->job) + { + GNUNET_CURL_job_cancel (dco->job); + dco->job = NULL; + } + GNUNET_free (dco->url); + GNUNET_free (dco); +} + + +/** + * Callback to process POST /dkg-commitment response + * + * @param cls the `struct FROSIX_DkgCommitmentRequestOperation` + * @param response_code HTTP response code, 0 on error + * @param data response body + * @param data_size number of byte in @a data +*/ +static void +handle_dkg_commitment_request_finished (void *cls, + long response_code, + const void *response) +{ + struct FROSIX_DkgCommitmentRequestOperation *dco = cls; + struct FROSIX_DkgCommitmentRequestDetails dcd; + const json_t *json_response = response; + + dco->job = NULL; + dcd.http_status = response_code; + dcd.ec = TALER_EC_NONE; + + switch (response_code) + { + case 0: + /* Hard error */ + GNUNET_break (0); + dcd.dcs = FROSIX_DCS_HTTP_ERROR; + dcd.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + case MHD_HTTP_CREATED: + { + dcd.dcs = FROSIX_DCS_SUCCESS; + dcd.provider_index = dco->provider_index; + + /* temp commitment struct */ + struct FROST_DkgCommitment commitment; + + /* We got a result, lets parse it */ + json_t *dkg_commitment = NULL; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_uint8 ("provider_index", + &dcd.dkg_commitment.identifier), + GNUNET_JSON_spec_json ("dkg_commitment", + &dkg_commitment), + GNUNET_JSON_spec_fixed_auto ("zkp_r", + &commitment.zkp.r), + GNUNET_JSON_spec_fixed_auto ("zkp_z", + &commitment.zkp.z), + GNUNET_JSON_spec_fixed_auto ("public_key", + &dcd.public_key), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (json_response, + spec, + NULL, + NULL)) + { + /* Parsing failed! */ + GNUNET_break_op (0); + dcd.http_status = 0; + GNUNET_JSON_parse_free (spec); + break; + } + + /* check if number of commitment values is in allowed range */ + if (0 >= json_array_size (dkg_commitment) + || json_array_size (dkg_commitment) >= 254) + { + GNUNET_break_op (0); + dcd.http_status = 0; + GNUNET_JSON_parse_free (spec); + break; + } + + dcd.dkg_commitment.shares_commitments_length = \ + (uint8_t) json_array_size (dkg_commitment); + + /* initialize struct dkg_commitment */ + FROST_initialize_dkg_commitment ( + &dcd.dkg_commitment, + dcd.dkg_commitment.identifier, + dcd.dkg_commitment.shares_commitments_length); + + /* copy back from temp commitment struct */ + memcpy (&dcd.dkg_commitment.zkp.r, + &commitment.zkp.r, + sizeof (commitment.zkp.r)); + memcpy (&dcd.dkg_commitment.zkp.z, + &commitment.zkp.z, + sizeof (commitment.zkp.z)); + + /* parse commitment values */ + for (unsigned int i = 0; i < dcd.dkg_commitment.shares_commitments_length; + i++) + { + struct GNUNET_JSON_Specification comm_spec[] = { + GNUNET_JSON_spec_fixed_auto (NULL, + &dcd.dkg_commitment.share_comm[i]), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (json_array_get (dkg_commitment, + i), + comm_spec, + NULL, + NULL)) + { + GNUNET_break_op (0); + GNUNET_JSON_parse_free (comm_spec); + GNUNET_JSON_parse_free (spec); + FROST_free_dkg_commitment (&dcd.dkg_commitment, + 1); + dcd.http_status = 0; + break; + } + + GNUNET_JSON_parse_free (comm_spec); + } + + GNUNET_JSON_parse_free (spec); + break; + } + case MHD_HTTP_BAD_REQUEST: + /* We have a conflict with the API */ + GNUNET_break (0); + dcd.dcs = FROSIX_DCS_CLIENT_ERROR; + dcd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* The provider has a problem! */ + GNUNET_break (0); + dcd.dcs = FROSIX_DCS_SERVER_ERROR; + dcd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + default: + /* Unexpected response code */ + GNUNET_break (0); + dcd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + } + + /* return to callback function with the data from the response */ + dco->cb (dco->cb_cls, + &dcd); + dco->cb = NULL; + + FROST_free_dkg_commitment (&dcd.dkg_commitment, + 1); + + FROSIX_dkg_commitment_request_cancel (dco); +} + + +/** + * Handle HTTP header received by curl. + * + * @param buffer one line of HTTP header data + * @param size size of an item + * @param userdata our `struct FROSIX_DkgCommitmentRequestOperation` + * @return `size * nitems` +*/ +static size_t +handle_header (char *buffer, + size_t size, + size_t nitems, + void *userdata) +{ + size_t total = size * nitems; + return total; +} + + +struct FROSIX_DkgCommitmentRequestOperation * +FROSIX_dkg_commitment_request ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct FROSIX_DkgRequestIdP *uuid, + uint8_t identifier, + uint8_t threshold, + uint8_t num_of_participants, + const struct FROSIX_DkgContextStringP *context_string, + const struct FROSIX_ChallengeHashP *challenge_hash, + const struct GNUNET_CRYPTO_EddsaPublicKey providers_public_keys[], + FROSIX_DkgCommitmentRequestCallback cb, + void *cb_cls) +{ + struct FROSIX_DkgCommitmentRequestOperation *dco; + CURL *eh; + char *json_str; + + /* check if we got a callback function, abort if not */ + GNUNET_assert (NULL != cb); + + dco = GNUNET_new (struct FROSIX_DkgCommitmentRequestOperation); + + { + /* prepare URL */ + char *uuid_str; + char *path; + + uuid_str = GNUNET_STRINGS_data_to_string_alloc (uuid, + sizeof (*uuid)); + + GNUNET_asprintf (&path, + "dkg-commitment/%s", + uuid_str); + + dco->url = TALER_url_join (backend_url, + path, + NULL); + + GNUNET_free (path); + GNUNET_free (uuid_str); + } + + dco->provider_index = identifier; + + /* array for all providers public keys */ + json_t *json_public_keys = json_array (); + + + for (unsigned int i = 0; i < num_of_participants; i++) + { + /* single public key */ + json_t *public_key; + public_key = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto (NULL, + &providers_public_keys[i])); + + /* add to public key array */ + GNUNET_assert (0 == + json_array_append_new ( + json_public_keys, + public_key)); + } + + { + /* pack the json object for the request body */ + json_t *dkg_commitment_data; + dkg_commitment_data = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("provider_index", + identifier), + GNUNET_JSON_pack_uint64 ("threshold", + threshold), + GNUNET_JSON_pack_data_auto ("context_string", + context_string), + GNUNET_JSON_pack_data_auto ("auth_hash", + challenge_hash), + GNUNET_JSON_pack_array_incref ("providers_public_keys", + json_public_keys)); + json_str = json_dumps (dkg_commitment_data, + JSON_COMPACT); + + json_decref (json_public_keys); + + /* check if we have a json object, abort if it was not successful */ + GNUNET_assert (NULL != json_str); + + json_decref (dkg_commitment_data); + } + + /* prepare curl options and fire the request */ + dco->ctx = ctx; + dco->cb = cb; + dco->cb_cls = cb_cls; + + eh = FROSIX_curl_easy_get_ (dco->url); + + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDS, + json_str)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDSIZE, + strlen (json_str))); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERFUNCTION, + &handle_header)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERDATA, + dco)); + + dco->job = GNUNET_CURL_job_add (ctx, + eh, + &handle_dkg_commitment_request_finished, + dco); + + return dco; +} +\ No newline at end of file diff --git a/src/restclient/frosix_api_dkg-key_delete.c b/src/restclient/frosix_api_dkg-key_delete.c @@ -0,0 +1,257 @@ +/* + This file is part of ANASTASIS + Copyright (C) 2014-2019 Anastasis SARL + + ANASTASIS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2.1, + or (at your option) any later version. + + ANASTASIS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with ANASTASIS; see the file COPYING.LGPL. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file restclient/frosix_api_dkg-key_delete.c + * @brief Implementation of the /dkg-key Delete + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + * @author Joel Urech + */ +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include "frosix_service.h" +#include "frost_high.h" +#include "frosix_api_curl_defaults.h" +#include <gnunet/gnunet_json_lib.h> +#include <taler/taler_json_lib.h> + + +/** + * @brief A Contract Operation Handle + */ +struct FROSIX_KeyDeleteOperation +{ + /** + * The url for this request, including parameters. + */ + char *url; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * The CURL context to connect to the backend + */ + struct GNUNET_CURL_Context *ctx; + + /** + * Function to call with the result. + */ + FROSIX_KeyDeleteCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; +}; + + +void +FROSIX_key_delete_cancel ( + struct FROSIX_KeyDeleteOperation *kdo) +{ + if (NULL != kdo->job) + { + GNUNET_CURL_job_cancel (kdo->job); + kdo->job = NULL; + } + GNUNET_free (kdo->url); + GNUNET_free (kdo); +} + + +/** + * Callback to process DELETE /dkg-key response + * + * @param cls the `struct FROSIX_DkgKeyStoreOperation` + * @param response_code HTTP response code, 0 on error + * @param data response body + * @param data_size number of byte in @a data +*/ +static void +handle_key_delete_finished (void *cls, + long response_code, + const void *response) +{ + struct FROSIX_KeyDeleteOperation *kdo = cls; + struct FROSIX_KeyDeleteDetails kdd; + const json_t *json_response = response; + + kdo->job = NULL; + kdd.http_status = response_code; + kdd.ec = TALER_EC_NONE; + + switch (response_code) + { + case 0: + /* Hard error */ + GNUNET_break (0); + kdd.kds = FROSIX_KDS_HTTP_ERROR; + kdd.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + case MHD_HTTP_NO_CONTENT: + case MHD_HTTP_OK: + { + kdd.kds = FROSIX_KDS_SUCCESS; + break; + } + case MHD_HTTP_BAD_REQUEST: + /* We have a conflict with the API */ + GNUNET_break (0); + kdd.kds = FROSIX_KDS_CLIENT_ERROR; + kdd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* The provider has a problem! */ + GNUNET_break (0); + kdd.kds = FROSIX_KDS_SERVER_ERROR; + kdd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + default: + /* Unexpected response code */ + GNUNET_break (0); + kdd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + } + + /* return to callback function with the data from the response */ + kdo->cb (kdo->cb_cls, + &kdd); + kdo->cb = NULL; + + FROSIX_key_delete_cancel (kdo); +} + + +/** + * Handle HTTP header received by curl. + * + * @param buffer one line of HTTP header data + * @param size size of an item + * @param userdata our `struct FROSIX_DkgKeyStoreOperation` + * @return `size * nitems` +*/ +static size_t +handle_header (char *buffer, + size_t size, + size_t nitems, + void *userdata) +{ + // struct FROSIX_DkgKeyStoreOperation *dko = userdata; + size_t total = size * nitems; + char *ndup; + const char *hdr_type; + char *hdr_val; + char *sp; + + ndup = GNUNET_strndup (buffer, + total); + + hdr_type = strtok_r (ndup, + ":", + &sp); + if (NULL == hdr_type) + { + GNUNET_free (ndup); + return total; + } + hdr_val = strtok_r (NULL, + "\n\r", + &sp); + if (NULL == hdr_val) + { + GNUNET_free (ndup); + return total; + } + if (' ' == *hdr_val) + hdr_val++; + /* ... FIXME */ + return total; +} + + +struct FROSIX_KeyDeleteOperation * +FROSIX_key_delete ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct FROSIX_DkgRequestIdP *uuid, + FROSIX_KeyDeleteCallback cb, + void *cb_cls) +{ + struct FROSIX_KeyDeleteOperation *kdo; + CURL *eh; + + /* check if we got a callback function, abort if not */ + GNUNET_assert (NULL != cb); + + kdo = GNUNET_new (struct FROSIX_KeyDeleteOperation); + { + /* prepare URL */ + char *uuid_str; + char *path; + + uuid_str = GNUNET_STRINGS_data_to_string_alloc (uuid, + sizeof (*uuid)); + + GNUNET_asprintf (&path, + "dkg-key/%s", + uuid_str); + + kdo->url = TALER_url_join (backend_url, + path, + NULL); + + GNUNET_free (path); + GNUNET_free (uuid_str); + } + + /* prepare curl options and fire the request */ + kdo->ctx = ctx; + kdo->cb = cb; + kdo->cb_cls = cb_cls; + + eh = FROSIX_curl_easy_get_ (kdo->url); + + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_CUSTOMREQUEST, + "DELETE")); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERDATA, + kdo)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERFUNCTION, + &handle_header)); + kdo->job = GNUNET_CURL_job_add (ctx, + eh, + &handle_key_delete_finished, + kdo); + + return kdo; +} +\ No newline at end of file diff --git a/src/restclient/frosix_api_dkg-key_store.c b/src/restclient/frosix_api_dkg-key_store.c @@ -0,0 +1,376 @@ +/* + This file is part of ANASTASIS + Copyright (C) 2014-2019 Anastasis SARL + + ANASTASIS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2.1, + or (at your option) any later version. + + ANASTASIS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with ANASTASIS; see the file COPYING.LGPL. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file restclient/frosix_api_dkg-key_store.c + * @brief Implementation of the /dkg-key POST + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + * @author Joel Urech + */ +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include "frosix_service.h" +#include "frost_high.h" +#include "frosix_api_curl_defaults.h" +#include <gnunet/gnunet_json_lib.h> +#include <taler/taler_json_lib.h> + + +/** + * @brief A Contract Operation Handle + */ +struct FROSIX_DkgKeyStoreOperation +{ + /** + * The url for this request, including parameters. + */ + char *url; + + /** + * FIXME + */ + uint8_t provider_index; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * The CURL context to connect to the backend + */ + struct GNUNET_CURL_Context *ctx; + + /** + * Function to call with the result. + */ + FROSIX_DkgKeyStoreCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; +}; + + +void +FROSIX_dkg_key_store_cancel ( + struct FROSIX_DkgKeyStoreOperation *dko) +{ + if (NULL != dko->job) + { + GNUNET_CURL_job_cancel (dko->job); + dko->job = NULL; + } + GNUNET_free (dko->url); + GNUNET_free (dko); +} + + +/** + * Callback to process POST /dkg-key response + * + * @param cls the `struct FROSIX_DkgKeyStoreOperation` + * @param response_code HTTP response code, 0 on error + * @param data response body + * @param data_size number of byte in @a data +*/ +static void +handle_dkg_key_store_finished (void *cls, + long response_code, + const void *response) +{ + struct FROSIX_DkgKeyStoreOperation *dko = cls; + struct FROSIX_DkgKeyStoreDetails dkd; + const json_t *json_response = response; + + dko->job = NULL; + dkd.http_status = response_code; + dkd.ec = TALER_EC_NONE; + + switch (response_code) + { + case 0: + /* Hard error */ + GNUNET_break (0); + dkd.dks = FROSIX_DKS_HTTP_ERROR; + dkd.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + case MHD_HTTP_CREATED: + case MHD_HTTP_OK: + { + dkd.dks = FROSIX_DKS_SUCCESS; + dkd.provider_index = dko->provider_index; + + /* We got a result, lets parse it */ + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("public_key", + &dkd.details.public_key), + GNUNET_JSON_spec_fixed_auto ("signature", + &dkd.details.signature), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (json_response, + spec, + NULL, + NULL)) + { + /* Parsing failed! */ + GNUNET_break_op (0); + dkd.http_status = 0; + GNUNET_JSON_parse_free (spec); + break; + } + + GNUNET_JSON_parse_free (spec); + break; + } + case MHD_HTTP_BAD_REQUEST: + /* We have a conflict with the API */ + GNUNET_break (0); + dkd.dks = FROSIX_DKS_CLIENT_ERROR; + dkd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* The provider has a problem! */ + GNUNET_break (0); + dkd.dks = FROSIX_DKS_SERVER_ERROR; + dkd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + default: + /* Unexpected response code */ + GNUNET_break (0); + dkd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + } + + /* return to callback function with the data from the response */ + dko->cb (dko->cb_cls, + &dkd); + dko->cb = NULL; + + FROSIX_dkg_key_store_cancel (dko); +} + + +/** + * Handle HTTP header received by curl. + * + * @param buffer one line of HTTP header data + * @param size size of an item + * @param userdata our `struct FROSIX_DkgKeyStoreOperation` + * @return `size * nitems` +*/ +static size_t +handle_header (char *buffer, + size_t size, + size_t nitems, + void *userdata) +{ + // struct FROSIX_DkgKeyStoreOperation *dko = userdata; + size_t total = size * nitems; + char *ndup; + const char *hdr_type; + char *hdr_val; + char *sp; + + ndup = GNUNET_strndup (buffer, + total); + + hdr_type = strtok_r (ndup, + ":", + &sp); + if (NULL == hdr_type) + { + GNUNET_free (ndup); + return total; + } + hdr_val = strtok_r (NULL, + "\n\r", + &sp); + if (NULL == hdr_val) + { + GNUNET_free (ndup); + return total; + } + if (' ' == *hdr_val) + hdr_val++; + /* ... FIXME */ + return total; +} + + +struct FROSIX_DkgKeyStoreOperation * +FROSIX_dkg_key_store ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct FROSIX_DkgRequestIdP *uuid, + uint8_t identifier, + uint8_t threshold, + uint8_t num_of_participants, + const struct FROSIX_DkgContextStringP *context_string, + const struct FROSIX_ChallengeHashP *challenge_hash, + const struct GNUNET_CRYPTO_EddsaPublicKey providers_public_keys[], + const struct FROSIX_EncryptionKey *encryption_key, + unsigned int expiration, + const struct FROSIX_DkgKeyStoreShare secret_shares[], + size_t len, + FROSIX_DkgKeyStoreCallback cb, + void *cb_cls) +{ + struct FROSIX_DkgKeyStoreOperation *dko; + CURL *eh; + char *json_str; + + /* check if we got a callback function, abort if not */ + GNUNET_assert (NULL != cb); + + dko = GNUNET_new (struct FROSIX_DkgKeyStoreOperation); + + { + /* prepare URL */ + char *uuid_str; + char *path; + + uuid_str = GNUNET_STRINGS_data_to_string_alloc (uuid, + sizeof (*uuid)); + + GNUNET_asprintf (&path, + "dkg-key/%s", + uuid_str); + + dko->url = TALER_url_join (backend_url, + path, + NULL); + + GNUNET_free (path); + GNUNET_free (uuid_str); + } + + dko->provider_index = identifier; + + /* array for all providers public keys */ + json_t *json_public_keys = json_array (); + + for (unsigned int i = 0; i < num_of_participants; i++) + { + /* single public key */ + json_t *public_key; + public_key = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto (NULL, + &providers_public_keys[i])); + + /* add to public key array */ + GNUNET_assert (0 == + json_array_append_new ( + json_public_keys, + public_key)); + } + + { + /* array for all secret shares */ + json_t *shares = json_array (); + + for (unsigned int i = 0; i < len; i++) + { + /* single secret share */ + json_t *share; + share = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("provider_index", + secret_shares[i].identifier), + GNUNET_JSON_pack_data_auto ("secret_share", + &secret_shares[i].secret_share), + GNUNET_JSON_pack_data_auto ("ephemeral_key", + &secret_shares[i].ephemeral_key)); + + /* add to secret shares array */ + GNUNET_assert (0 == + json_array_append_new ( + shares, + share)); + } + + /* pack the json object for the request body */ + json_t *dkg_key_data; + dkg_key_data = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("provider_index", + identifier), + GNUNET_JSON_pack_uint64 ("threshold", + threshold), + GNUNET_JSON_pack_data_auto ("context_string", + context_string), + GNUNET_JSON_pack_data_auto ("auth_hash", + challenge_hash), + GNUNET_JSON_pack_array_steal ("providers_public_keys", + json_public_keys), + GNUNET_JSON_pack_data_auto ("pre_encryption_key", + encryption_key), + GNUNET_JSON_pack_uint64 ("expiration", + expiration), + GNUNET_JSON_pack_array_steal ("secret_shares", + shares)); + + json_str = json_dumps (dkg_key_data, + JSON_COMPACT); + + /* check if we have a json object, abort if it was not successful */ + GNUNET_assert (NULL != json_str); + + json_decref (dkg_key_data); + } + + /* prepare curl options and fire the request */ + dko->ctx = ctx; + dko->cb = cb; + dko->cb_cls = cb_cls; + + eh = FROSIX_curl_easy_get_ (dko->url); + + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDS, + json_str)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDSIZE, + strlen (json_str))); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERFUNCTION, + &handle_header)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERDATA, + dko)); + + dko->job = GNUNET_CURL_job_add (ctx, + eh, + &handle_dkg_key_store_finished, + dko); + + return dko; +} +\ No newline at end of file diff --git a/src/restclient/frosix_api_dkg-share_request.c b/src/restclient/frosix_api_dkg-share_request.c @@ -0,0 +1,443 @@ +/* + This file is part of ANASTASIS + Copyright (C) 2014-2019 Anastasis SARL + + ANASTASIS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2.1, + or (at your option) any later version. + + ANASTASIS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with ANASTASIS; see the file COPYING.LGPL. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file restclient/frosix_api_dkg-share_request.c + * @brief Implementation of the /dkg-share POST + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + * @author Joel Urech + */ +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include "frosix_service.h" +#include "frost_high.h" +#include "frosix_api_curl_defaults.h" +#include <gnunet/gnunet_json_lib.h> +#include <taler/taler_json_lib.h> + + +/** + * @brief A Contract Operation Handle + */ +struct FROSIX_DkgShareRequestOperation +{ + /** + * The url for this request, including parameters. + */ + char *url; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * Provider index + */ + uint8_t provider_index; + + /** + * The CURL context to connect to the backend + */ + struct GNUNET_CURL_Context *ctx; + + /** + * Function to call with the result. + */ + FROSIX_DkgShareRequestCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; +}; + + +void +FROSIX_dkg_share_request_cancel ( + struct FROSIX_DkgShareRequestOperation *dso) +{ + if (NULL != dso->job) + { + GNUNET_CURL_job_cancel (dso->job); + dso->job = NULL; + } + GNUNET_free (dso->url); + GNUNET_free (dso); +} + + +/** + * Callback to process POST /dkg-share response + * + * @param cls the `struct FROSIX_DkgShareRequestOperation` + * @param response_code HTTP response code, 0 on error + * @param data response body + * @param data_size number of byte in @a data +*/ +static void +handle_dkg_share_request_finished (void *cls, + long response_code, + const void *response) +{ + struct FROSIX_DkgShareRequestOperation *dso = cls; + struct FROSIX_DkgShareRequestDetails dsd; + const json_t *json_response = response; + + dso->job = NULL; + dsd.http_status = response_code; + dsd.ec = TALER_EC_NONE; + + switch (response_code) + { + case 0: + /* Hard error */ + GNUNET_break (0); + dsd.dss = FROSIX_DSS_HTTP_ERROR; + dsd.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + case MHD_HTTP_CREATED: + case MHD_HTTP_OK: + { + dsd.dss = FROSIX_DSS_SUCCESS; + dsd.provider_index = dso->provider_index; + + /* We got a result, lets parse it */ + json_t *secret_shares = NULL; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_json ("secret_shares", + &secret_shares), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (json_response, + spec, + NULL, + NULL)) + { + /* Parsing failed! */ + GNUNET_break_op (0); + dsd.http_status = 0; + GNUNET_JSON_parse_free (spec); + break; + } + + /* check if size of array is in allowed range */ + if (0 >= json_array_size (secret_shares) + || json_array_size (secret_shares) >= 254) + { + GNUNET_break_op (0); + dsd.http_status = 0; + GNUNET_JSON_parse_free (spec); + break; + } + + dsd.shares_len = json_array_size (secret_shares); + + /* allocate memory */ + dsd.shares = GNUNET_malloc (dsd.shares_len * sizeof (*dsd.shares)); + GNUNET_assert (NULL != dsd.shares); + + for (unsigned int i = 0; i < dsd.shares_len; i++) + { + struct GNUNET_JSON_Specification share_spec[] = { + GNUNET_JSON_spec_uint8 ("target", + &dsd.shares[i].target), + GNUNET_JSON_spec_uint8 ("issuer", + &dsd.shares[i].issuer), + GNUNET_JSON_spec_fixed_auto ("secret_share", + &dsd.shares[i].encrypted_share), + GNUNET_JSON_spec_fixed_auto ("ephemeral_key", + &dsd.shares[i].ephemeral_key), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (json_array_get (secret_shares, + i), + share_spec, + NULL, + NULL)) + { + GNUNET_break_op (0); + GNUNET_JSON_parse_free (share_spec); + GNUNET_JSON_parse_free (spec); + dsd.http_status = 0; + break; + } + + GNUNET_JSON_parse_free (share_spec); + } + + GNUNET_JSON_parse_free (spec); + + break; + } + case MHD_HTTP_BAD_REQUEST: + /* We have a conflict with the API */ + GNUNET_break (0); + dsd.dss = FROSIX_DSS_CLIENT_ERROR; + dsd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* The provider has a problem! */ + GNUNET_break (0); + dsd.dss = FROSIX_DSS_SERVER_ERROR; + dsd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + default: + /* Unexpected response code */ + GNUNET_break (0); + dsd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + } + + /* return to callback function with the data from the response */ + dso->cb (dso->cb_cls, + &dsd); + dso->cb = NULL; + + FROSIX_dkg_share_request_cancel (dso); +} + + +/** + * Handle HTTP header received by curl. + * + * @param buffer one line of HTTP header data + * @param size size of an item + * @param userdata our `struct FROSIX_DkgShareRequestOperation` + * @return `size * nitems` +*/ +static size_t +handle_header (char *buffer, + size_t size, + size_t nitems, + void *userdata) +{ + // struct FROSIX_DkgShareRequestOperation *dso = userdata; + size_t total = size * nitems; + char *ndup; + const char *hdr_type; + char *hdr_val; + char *sp; + + ndup = GNUNET_strndup (buffer, + total); + + hdr_type = strtok_r (ndup, + ":", + &sp); + if (NULL == hdr_type) + { + GNUNET_free (ndup); + return total; + } + hdr_val = strtok_r (NULL, + "\n\r", + &sp); + if (NULL == hdr_val) + { + GNUNET_free (ndup); + return total; + } + if (' ' == *hdr_val) + hdr_val++; + /* ... FIXME */ + return total; +} + + +struct FROSIX_DkgShareRequestOperation * +FROSIX_dkg_share_request ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct FROSIX_DkgRequestIdP *uuid, + uint8_t identifier, + uint8_t threshold, + uint8_t num_of_participants, + const struct FROSIX_DkgContextStringP *context_string, + const struct FROSIX_ChallengeHashP *challenge_hash, + const struct FROSIX_DkgCommitment dkg_commitments[], + size_t len, + const struct GNUNET_CRYPTO_EddsaPublicKey providers_public_keys[], + FROSIX_DkgShareRequestCallback cb, + void *cb_cls) +{ + struct FROSIX_DkgShareRequestOperation *dso; + CURL *eh; + char *json_str; + + /* check if we got a callback function, abort if not */ + GNUNET_assert (NULL != cb); + + dso = GNUNET_new (struct FROSIX_DkgShareRequestOperation); + + { + /* prepare URL */ + char *uuid_str; + char *path; + + uuid_str = GNUNET_STRINGS_data_to_string_alloc (uuid, + sizeof (*uuid)); + + GNUNET_asprintf (&path, + "dkg-shares/%s", + uuid_str); + + dso->url = TALER_url_join (backend_url, + path, + NULL); + + GNUNET_free (path); + GNUNET_free (uuid_str); + } + + dso->provider_index = identifier; + + /* array for all providers public keys */ + json_t *json_public_keys = json_array (); + + for (unsigned int i = 0; i < num_of_participants; i++) + { + /* single public key */ + json_t *public_key; + public_key = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto (NULL, + &providers_public_keys[i])); + + /* add to public key array */ + GNUNET_assert (0 == + json_array_append_new ( + json_public_keys, + public_key)); + } + + { + /* array for all dkg commitments */ + json_t *commitments = json_array (); + + for (unsigned int i = 0; i < len; i++) + { + /* dkg commitment values */ + json_t *commitment_values = json_array (); + for (unsigned int j = 0; + j < dkg_commitments[i].commitment.shares_commitments_length; + j++) + { + /* single commitment value */ + json_t *temp_value = json_object (); + temp_value = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ( + NULL, + &dkg_commitments[i].commitment.share_comm[j])); + + /* add to commitment_values array */ + GNUNET_assert (0 == + json_array_append_new ( + commitment_values, + temp_value)); + } + + /* single dkg commitment */ + json_t *dkg_commitment; + dkg_commitment = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("provider_index", + dkg_commitments[i].commitment.identifier), + GNUNET_JSON_pack_array_steal ("dkg_commitment", + commitment_values), + GNUNET_JSON_pack_data_auto ("zkp_r", + &dkg_commitments[i].commitment.zkp.r), + GNUNET_JSON_pack_data_auto ("zkp_z", + &dkg_commitments[i].commitment.zkp.z), + GNUNET_JSON_pack_data_auto ("public_key", + &dkg_commitments[i].encryption_public_key)); + + /* add to commitments array */ + GNUNET_assert (0 == + json_array_append_new ( + commitments, + dkg_commitment)); + } + + /* pack the json object for the request body */ + json_t *dkg_share_data; + dkg_share_data = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("provider_index", + identifier), + GNUNET_JSON_pack_uint64 ("threshold", + threshold), + GNUNET_JSON_pack_uint64 ("num_of_participants", + num_of_participants), + GNUNET_JSON_pack_data_auto ("context_string", + context_string), + GNUNET_JSON_pack_data_auto ("auth_hash", + challenge_hash), + GNUNET_JSON_pack_array_steal ("providers_public_keys", + json_public_keys), + GNUNET_JSON_pack_array_steal ("dkg_commitments", + commitments)); + + json_str = json_dumps (dkg_share_data, + JSON_COMPACT); + + /* check if we have a json object, abort if it was not successful */ + GNUNET_assert (NULL != json_str); + + json_decref (dkg_share_data); + } + + /* prepare curl options and fire the request */ + dso->ctx = ctx; + dso->cb = cb; + dso->cb_cls = cb_cls; + + eh = FROSIX_curl_easy_get_ (dso->url); + + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDS, + json_str)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDSIZE, + strlen (json_str))); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERFUNCTION, + &handle_header)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERDATA, + dso)); + + dso->job = GNUNET_CURL_job_add (ctx, + eh, + &handle_dkg_share_request_finished, + dso); + + return dso; +} +\ No newline at end of file diff --git a/src/restclient/frosix_api_seed_get.c b/src/restclient/frosix_api_seed_get.c @@ -0,0 +1,155 @@ +/* + This file is part of ANASTASIS + Copyright (C) 2014-2019 Anastasis SARL + + ANASTASIS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2.1, + or (at your option) any later version. + + ANASTASIS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with ANASTASIS; see the file COPYING.LGPL. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file restclient/frosix_api_seed_get.c + * @brief Implementation of the /policy GET and POST + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + */ +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include "frosix_service.h" +#include "frosix_api_curl_defaults.h" + + +void +FROSIX_seed_get_cancel (struct FROSIX_SeedGetOperation *sgo) +{ + if (NULL != sgo->job) + { + GNUNET_CURL_job_cancel (sgo->job); + sgo->job = NULL; + } + GNUNET_free (sgo->url); + GNUNET_free (sgo); +} + + +/** + * Process GET /seed response + */ +static void +handle_seed_get_finished (void *cls, + long response_code, + const void *data, + size_t data_size) +{ + struct FROSIX_SeedGetOperation *sgo = cls; + + sgo->job = NULL; + switch (response_code) + { + case 0: + /* Hard error */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Backend didn't even return from GET /seed\n"); + break; + case MHD_HTTP_OK: + { + struct FROSIX_ProviderSeed ps; + + if (sizeof (*ps.seed) != data_size) + { + GNUNET_break_op (0); + response_code = 0; + break; + } + /* Sucess, call callback with all details! */ + ps.provider_index = sgo->provider_index; + memset (&ps.seed, 0, sizeof (ps.seed)); + ps.seed = data; + + sgo->cb (sgo->cb_cls, + response_code, + &ps); + sgo->cb = NULL; + FROSIX_seed_get_cancel (sgo); + return; + } + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the anastasis server is buggy + (or API version conflict); just pass JSON reply to the application */ + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify */ + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + (unsigned int) response_code); + GNUNET_break (0); + response_code = 0; + break; + } + sgo->cb (sgo->cb_cls, + response_code, + NULL); + sgo->cb = NULL; + FROSIX_seed_get_cancel (sgo); +} + + +struct FROSIX_SeedGetOperation * +FROSIX_seed_get ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + uint8_t provider_index, + FROSIX_SeedGetCallback cb, + void *cb_cls) +{ + struct FROSIX_SeedGetOperation *sgo; + + GNUNET_assert (NULL != cb); + sgo = GNUNET_new (struct FROSIX_SeedGetOperation); + sgo->url = TALER_url_join (backend_url, + "seed", + NULL); + sgo->provider_index = provider_index; + + sgo->ctx = ctx; + sgo->cb = cb; + sgo->cb_cls = cb_cls; + { + CURL *eh; + + eh = FROSIX_curl_easy_get_ (sgo->url); + sgo->job = GNUNET_CURL_job_add_raw (ctx, + eh, + NULL, + &handle_seed_get_finished, + sgo); + } + + if (NULL == sgo->job) + { + GNUNET_free (sgo->url); + GNUNET_free (sgo); + return NULL; + } + + return sgo; +} diff --git a/src/restclient/frosix_api_sig-commitment_request.c b/src/restclient/frosix_api_sig-commitment_request.c @@ -0,0 +1,363 @@ +/* + This file is part of ANASTASIS + Copyright (C) 2014-2019 Anastasis SARL + + ANASTASIS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2.1, + or (at your option) any later version. + + ANASTASIS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with ANASTASIS; see the file COPYING.LGPL. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file restclient/frosix_api_sig-commitment_request.c + * @brief Implementation of the /sig-commitment POST + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + * @author Joel Urech + */ +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include "frosix_service.h" +#include "frost_high.h" +#include "frosix_api_curl_defaults.h" +#include <gnunet/gnunet_json_lib.h> +#include <taler/taler_json_lib.h> + + +/** + * @brief A Contract Operation Handle + */ +struct FROSIX_SigCommitmentRequestOperation +{ + /** + * The url for this request, including parameters. + */ + char *url; + + /** + * Index of the provider. + */ + uint8_t provider_index; + + /** + * Index in the provider array. + */ + uint8_t array_index; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * The CURL context to connect to the backend + */ + struct GNUNET_CURL_Context *ctx; + + /** + * Function to call with the result. + */ + FROSIX_SigCommitmentRequestCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; +}; + + +void +FROSIX_sig_commitment_request_cancel ( + struct FROSIX_SigCommitmentRequestOperation *sco) +{ + if (NULL != sco->job) + { + GNUNET_CURL_job_cancel (sco->job); + sco->job = NULL; + } + GNUNET_free (sco->url); + GNUNET_free (sco); +} + + +/** + * Callback to process POST /sig-commitment response + * + * @param cls the `struct FROSIX_SigCommitmentRequestOperation` + * @param response_code HTTP response code, 0 on error + * @param data response body + * @param data_size number of byte in @a data +*/ +static void +handle_sig_commitment_request_finished (void *cls, + long response_code, + const void *response) +{ + struct FROSIX_SigCommitmentRequestOperation *sco = cls; + struct FROSIX_SigCommitmentRequestDetails scd; + const json_t *json_response = response; + + sco->job = NULL; + scd.http_status = response_code; + scd.ec = TALER_EC_NONE; + scd.array_index = sco->array_index; + scd.sig_commitment.identifier = sco->provider_index; + + switch (response_code) + { + case 0: + /* Hard error */ + GNUNET_break (0); + scd.scs = FROSIX_SCS_HTTP_ERROR; + scd.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + case MHD_HTTP_CREATED: + case MHD_HTTP_OK: + { + scd.scs = FROSIX_SCS_SUCCESS; + + /* We got a result, lets parse it */ + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("hiding_commitment", + &scd.sig_commitment.hiding_commitment), + GNUNET_JSON_spec_fixed_auto ("binding_commitment", + &scd.sig_commitment.binding_commitment), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (json_response, + spec, + NULL, + NULL)) + { + /* Parsing failed! */ + GNUNET_break_op (0); + scd.http_status = 0; + GNUNET_JSON_parse_free (spec); + break; + } + + GNUNET_JSON_parse_free (spec); + break; + } + case MHD_HTTP_BAD_REQUEST: + /* We have a conflict with the API */ + scd.http_status = 0; + GNUNET_break (0); + scd.scs = FROSIX_SCS_CLIENT_ERROR; + scd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* The provider has a problem! */ + scd.http_status = 0; + GNUNET_break (0); + scd.scs = FROSIX_SCS_SERVER_ERROR; + scd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + default: + /* Unexpected response code */ + scd.http_status = 0; + GNUNET_break (0); + scd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + } + + /* return to callback function with the data from the response */ + sco->cb (sco->cb_cls, + &scd); + sco->cb = NULL; + + FROSIX_sig_commitment_request_cancel (sco); + return; +} + +/** + * Handle HTTP header received by curl. + * + * @param buffer one line of HTTP header data + * @param size size of an item + * @param userdata our `struct FROSIX_DkgCommitmentRequestOperation` + * @return `size * nitems` +*/ +static size_t +handle_header (char *buffer, + size_t size, + size_t nitems, + void *userdata) +{ + // struct FROSIX_DkgCommitmentRequestOperation *dco = userdata; + size_t total = size * nitems; + return total; + + /*char *ndup; + const char *hdr_type; + char *hdr_val; + char *sp; + + ndup = GNUNET_strndup (buffer, + total); + + hdr_type = strtok_r (ndup, + ":", + &sp); + if (NULL == hdr_type) + { + GNUNET_free (ndup); + return total; + } + hdr_val = strtok_r (NULL, + "\n\r", + &sp); + if (NULL == hdr_val) + { + GNUNET_free (ndup); + return total; + } + if (' ' == *hdr_val) + hdr_val++; + + return total;*/ +} + + +struct FROSIX_SigCommitmentRequestOperation * +FROSIX_sig_commitment_request ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct FROSIX_SigRequestIdP *uuid, + uint8_t provider_index, + uint8_t array_index, + const struct FROST_HashCode *encryption_key_hash, + const struct GNUNET_HashCode *auth_data, + const struct GNUNET_CRYPTO_Edx25519PublicKey *auth_pub, + const struct GNUNET_CRYPTO_Edx25519Signature *auth_sig, + const char *auth_method, + const struct FROST_MessageHash *message_hash, + FROSIX_SigCommitmentRequestCallback cb, + void *cb_cls) +{ + struct FROSIX_SigCommitmentRequestOperation *sco; + CURL *eh; + char *json_str; + + /* check if we got a callback function, abort if not */ + GNUNET_assert (NULL != cb); + + sco = GNUNET_new (struct FROSIX_SigCommitmentRequestOperation); + sco->array_index = array_index; + sco->provider_index = provider_index; + + { + /* prepare URL */ + char *uuid_str; + char *path; + + uuid_str = GNUNET_STRINGS_data_to_string_alloc (uuid, + sizeof (*uuid)); + + GNUNET_asprintf (&path, + "sig-commitment/%s", + uuid_str); + + sco->url = TALER_url_join (backend_url, + path, + NULL); + + GNUNET_free (path); + GNUNET_free (uuid_str); + } + + if (0 == strcmp (auth_method, + "question")) + { + /* pack the json object for the request body */ + json_t *sig_commitment_data; + sig_commitment_data = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("encryption_key_hash", + encryption_key_hash), + GNUNET_JSON_pack_string ("auth_method", + auth_method), + GNUNET_JSON_pack_data_auto ("auth_pub", + auth_pub), + GNUNET_JSON_pack_data_auto ("auth_sig", + auth_sig), + GNUNET_JSON_pack_data_auto ("message_hash", + message_hash)); + + json_str = json_dumps (sig_commitment_data, + JSON_COMPACT); + + /* check if we have a json object, abort if it was not successful */ + GNUNET_assert (NULL != json_str); + + json_decref (sig_commitment_data); + } + else + { + /* pack the json object for the request body */ + json_t *sig_commitment_data; + sig_commitment_data = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("encryption_key_hash", + encryption_key_hash), + GNUNET_JSON_pack_string ("auth_method", + auth_method), + GNUNET_JSON_pack_data_auto ("auth_data", + auth_data), + GNUNET_JSON_pack_data_auto ("message_hash", + message_hash)); + + json_str = json_dumps (sig_commitment_data, + JSON_COMPACT); + + /* check if we have a json object, abort if it was not successful */ + GNUNET_assert (NULL != json_str); + + json_decref (sig_commitment_data); + } + + /* prepare curl options and fire the request */ + sco->ctx = ctx; + sco->cb = cb; + sco->cb_cls = cb_cls; + + eh = FROSIX_curl_easy_get_ (sco->url); + + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDS, + json_str)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDSIZE, + strlen (json_str))); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERFUNCTION, + &handle_header)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERDATA, + sco)); + + sco->job = GNUNET_CURL_job_add (ctx, + eh, + &handle_sig_commitment_request_finished, + sco); + + return sco; +} +\ No newline at end of file diff --git a/src/restclient/frosix_api_sig-share_request.c b/src/restclient/frosix_api_sig-share_request.c @@ -0,0 +1,353 @@ +/* + This file is part of ANASTASIS + Copyright (C) 2014-2019 Anastasis SARL + + ANASTASIS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2.1, + or (at your option) any later version. + + ANASTASIS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with ANASTASIS; see the file COPYING.LGPL. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file restclient/frosix_api_sig-share_request.c + * @brief Implementation of the /sig-share POST + * @author Christian Grothoff + * @author Dennis Neufeld + * @author Dominik Meister + * @author Joel Urech + */ +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include "frosix_service.h" +#include "frost_high.h" +#include "frosix_api_curl_defaults.h" +#include <gnunet/gnunet_json_lib.h> +#include <taler/taler_json_lib.h> + + +/** + * @brief A Contract Operation Handle + */ +struct FROSIX_SigShareRequestOperation +{ + /** + * The url for this request, including parameters. + */ + char *url; + + /** + * Position in the array. + */ + uint8_t array_index; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * The CURL context to connect to the backend + */ + struct GNUNET_CURL_Context *ctx; + + /** + * Function to call with the result. + */ + FROSIX_SigShareRequestCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Identifier of the provider + */ + uint8_t provider_index; +}; + + +void +FROSIX_sig_share_request_cancel ( + struct FROSIX_SigShareRequestOperation *sso) +{ + if (NULL != sso->job) + { + GNUNET_CURL_job_cancel (sso->job); + sso->job = NULL; + } + GNUNET_free (sso->url); + GNUNET_free (sso); +} + + +/** + * Callback to process POST /sig-share response + * + * @param cls the `struct FROSIX_SigShareRequestOperation` + * @param response_code HTTP response code, 0 on error + * @param data response body + * @param data_size number of byte in @a data +*/ +static void +handle_sig_share_request_finished (void *cls, + long response_code, + const void *response) +{ + struct FROSIX_SigShareRequestOperation *sso = cls; + struct FROSIX_SigShareRequestDetails ssd; + const json_t *json_response = response; + + sso->job = NULL; + ssd.http_status = response_code; + ssd.ec = TALER_EC_NONE; + ssd.array_index = sso->array_index; + ssd.sig_share.identifier = sso->provider_index; + + switch (response_code) + { + case 0: + /* Hard error */ + GNUNET_break (0); + ssd.sss = FROSIX_SSS_HTTP_ERROR; + ssd.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + case MHD_HTTP_CREATED: + case MHD_HTTP_OK: + { + ssd.sss = FROSIX_SSS_SUCCESS; + + /* We got a result, lets parse it */ + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("signature_share", + &ssd.sig_share.sig_share), + GNUNET_JSON_spec_fixed_auto ("public_key_share", + &ssd.sig_share.pk_i), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (json_response, + spec, + NULL, + NULL)) + { + /* Parsing failed! */ + GNUNET_break_op (0); + ssd.http_status = 0; + GNUNET_JSON_parse_free (spec); + break; + } + + GNUNET_JSON_parse_free (spec); + break; + } + case MHD_HTTP_BAD_REQUEST: + /* We have a conflict with the API */ + GNUNET_break (0); + ssd.sss = FROSIX_SSS_CLIENT_ERROR; + ssd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* The provider has a problem! */ + GNUNET_break (0); + ssd.sss = FROSIX_SSS_SERVER_ERROR; + ssd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + default: + /* Unexpected response code */ + GNUNET_break (0); + ssd.ec = TALER_JSON_get_error_code2 (json_response, + json_object_size (json_response)); + break; + } + + /* return to callback function with the data from the response */ + sso->cb (sso->cb_cls, + &ssd); + sso->cb = NULL; + + FROSIX_sig_share_request_cancel (sso); + return; +} + + +/** + * Handle HTTP header received by curl. + * + * @param buffer one line of HTTP header data + * @param size size of an item + * @param userdata our `struct FROSIX_SigShareRequestOperation` + * @return `size * nitems` +*/ +static size_t +handle_header (char *buffer, + size_t size, + size_t nitems, + void *userdata) +{ + // struct FROSIX_SigShareRequestOperation *sso = userdata; + size_t total = size * nitems; + char *ndup; + const char *hdr_type; + char *hdr_val; + char *sp; + + ndup = GNUNET_strndup (buffer, + total); + + hdr_type = strtok_r (ndup, + ":", + &sp); + if (NULL == hdr_type) + { + GNUNET_free (ndup); + return total; + } + hdr_val = strtok_r (NULL, + "\n\r", + &sp); + if (NULL == hdr_val) + { + GNUNET_free (ndup); + return total; + } + if (' ' == *hdr_val) + hdr_val++; + /* ... FIXME */ + return total; +} + + +struct FROSIX_SigShareRequestOperation * +FROSIX_sig_share_request ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const struct FROSIX_SigRequestIdP *uuid, + uint8_t provider_index, + uint8_t array_index, + const struct FROSIX_EncryptionKey *encryption_key, + const struct FROST_MessageHash *message_hash, + const struct FROST_Commitment commitments[], + size_t len, + FROSIX_SigShareRequestCallback cb, + void *cb_cls) +{ + struct FROSIX_SigShareRequestOperation *sso; + CURL *eh; + char *json_str; + + /* check if we got a callback function, abort if not */ + GNUNET_assert (NULL != cb); + + sso = GNUNET_new (struct FROSIX_SigShareRequestOperation); + sso->array_index = array_index; + sso->provider_index = provider_index; + + { + /* prepare URL */ + char *uuid_str; + char *path; + + uuid_str = GNUNET_STRINGS_data_to_string_alloc (uuid, + sizeof (*uuid)); + + GNUNET_asprintf (&path, + "sig-share/%s", + uuid_str); + + sso->url = TALER_url_join (backend_url, + path, + NULL); + + GNUNET_free (path); + GNUNET_free (uuid_str); + } + + { + /* array for all packed commitments */ + json_t *commits = json_array (); + + for (unsigned int i = 0; i < len; i++) + { + /* single commitment */ + json_t *commit; + commit = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_uint64 ("identifier", + commitments[i].identifier), + GNUNET_JSON_pack_data_auto ("hiding_commitment", + &commitments[i].hiding_commitment), + GNUNET_JSON_pack_data_auto ("binding_commitment", + &commitments[i].binding_commitment)); + + /* add to commitments array */ + GNUNET_assert (0 == + json_array_append_new ( + commits, + commit)); + } + + { + /* pack the json object for the request body */ + json_t *sig_share_data; + sig_share_data = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("encryption_key", + encryption_key), + GNUNET_JSON_pack_data_auto ("message_hash", + message_hash), + GNUNET_JSON_pack_array_steal ("commitments", + commits)); + + json_str = json_dumps (sig_share_data, + JSON_COMPACT); + + /* check if we have a json object, abort if it was not successful */ + GNUNET_assert (NULL != json_str); + + json_decref (sig_share_data); + } + } + + /* prepare curl options and fire the request */ + sso->ctx = ctx; + sso->cb = cb; + sso->cb_cls = cb_cls; + + eh = FROSIX_curl_easy_get_ (sso->url); + + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDS, + json_str)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDSIZE, + strlen (json_str))); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERFUNCTION, + &handle_header)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERDATA, + sso)); + + sso->job = GNUNET_CURL_job_add (ctx, + eh, + &handle_sig_share_request_finished, + sso); + + return sso; +} +\ No newline at end of file diff --git a/src/restclient/test_frosix.c b/src/restclient/test_frosix.c @@ -0,0 +1,236 @@ +/** + * +*/ +#include <stdio.h> +#include <string.h> +#include <time.h> +#include "frosix_service.h" +#include "frosix_backend.h" +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_curl_lib.h> +#include "platform.h" +#include "frost_high.h" + +#define HASHCONTEXTVAL "FROSIX-DKG-ID" + + +/** + * State for a "config" CMD. + */ +struct ConfigState +{ + /** + * The interpreter state. + */ + struct GNUNET_CURL_Context *ctx; + + struct GNUNET_CURL_RescheduleContext *rc; + + /** + * URL of the frosix backend. + */ + const char *frosix_url; + + /** + * Expected status code. + */ + unsigned int http_status; + + /** + * The /config GET operation handle. + */ + struct FROSIX_ConfigOperation *so; + + /** + * The salt value from server. + */ + struct FROSIX_ProviderSaltP provider_salt; +}; + +static void +config_cb (void *cls, + unsigned int http_status, + const struct FROSIX_Config *config) +{ + fprintf (stderr, "test\n"); + struct ConfigState *ss = cls; + + ss->so = NULL; + if (http_status != ss->http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u", + http_status); + return; + } + if (NULL == config) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Config is NULL"); + return; + } + ss->provider_salt = config->provider_salt; + +} + + +int +main (void) +{ + GNUNET_log_setup ("WARNING", + NULL, + NULL); + + struct ConfigState *ss; + ss = GNUNET_new (struct ConfigState); + ss->frosix_url = "http://localhost:9977/"; + ss->http_status = MHD_HTTP_OK; + ss->ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, + &ss->rc); + + /*ss->so = FROSIX_get_config (&ss->ctx, + ss->frosix_url, + &config_cb, + ss);*/ + + FROST_init (); + + uint8_t identifier = 1; + uint8_t num_of_participants = 5; + uint8_t threshold = 3; + + /* Challenge Method */ + struct FROST_Scalar scalar_method; + FROST_scalar_random (&scalar_method); + + struct FROST_HashCode challenge_method; + struct FROST_HashState state_method; + FROST_hash_init (&state_method); + FROST_hash_scalar_update (&state_method, &scalar_method); + FROST_hash_final (&state_method, &challenge_method); + + /*Convert to crockford 32 and print*/ + char *chall_method; + chall_method = GNUNET_STRINGS_data_to_string_alloc (&challenge_method, + sizeof (challenge_method)); + fprintf (stderr, "challenge_method: %s\n", chall_method); + + /* Challenge Data */ + struct FROST_Scalar scalar_data; + FROST_scalar_random (&scalar_data); + + struct FROST_HashCode challenge_data; + struct FROST_HashState state_data; + FROST_hash_init (&state_data); + FROST_hash_scalar_update (&state_data, &scalar_data); + FROST_hash_final (&state_data, &challenge_data); + + /*Convert to crockford 32 and print*/ + char *chall_data; + chall_data = GNUNET_STRINGS_data_to_string_alloc (&challenge_data, + sizeof (challenge_data)); + fprintf (stderr, "challenge_data: %s\n", chall_data); + + /* Context String*/ + struct FROST_Scalar scalar_context; + FROST_scalar_random (&scalar_context); + + struct FROST_HashCode context_string; + struct FROST_HashState state_context; + FROST_hash_init (&state_context); + FROST_hash_scalar_update (&state_context, &scalar_context); + FROST_hash_final (&state_context, &context_string); + + /*Convert to crockford 32 and print*/ + char *chall_context; + chall_context = GNUNET_STRINGS_data_to_string_alloc (&context_string, + sizeof (context_string)); + fprintf (stderr, "context_string: %s\n", chall_context); + + /* ID */ + char *secret = "gUfO1KGOKYIFlFQg"; + struct FROSIX_ProviderSaltP provider_salt; + + GNUNET_CRYPTO_kdf (&provider_salt, + sizeof (provider_salt), + "frosix-provider-salt", + strlen ("frosix-provider-salt"), + secret, + strlen (secret), + NULL, + 0); + + struct FROST_HashState id_state; + struct FROST_HashCode id; + + FROST_hash_init (&id_state); + FROST_hash_hash_update (&id_state, + &context_string); + FROST_hash_hash_update (&id_state, + &challenge_method); + FROST_hash_hash_update (&id_state, + &challenge_data); + FROST_hash_uint8_update (&id_state, + identifier); + FROST_hash_uint8_update (&id_state, + num_of_participants); + FROST_hash_uint8_update (&id_state, + threshold); + FROST_hash_fixed_update (&id_state, + &provider_salt.salt, + sizeof (provider_salt.salt)); + FROST_hash_fixed_update (&id_state, + HASHCONTEXTVAL, + sizeof (HASHCONTEXTVAL)); + FROST_hash_final (&id_state, + &id); + + /*Convert to crockford 32 and print*/ + char *crock_id; + crock_id = GNUNET_STRINGS_data_to_string_alloc (&id, + sizeof (id)); + fprintf (stderr, "caller_id: %s\n", crock_id); + + /* Encryption Key */ + struct FROST_Scalar enc_key; + FROST_scalar_random (&enc_key); + + /* Convert to crockford 32 and print */ + char *crock_key; + crock_key = GNUNET_STRINGS_data_to_string_alloc (&enc_key, + sizeof (enc_key)); + fprintf (stderr, "encryption_key: %s\n", crock_key); + + /* Random signing keys */ + struct GNUNET_CRYPTO_EddsaPrivateKey private_key; + struct GNUNET_CRYPTO_EddsaPublicKey public_key; + GNUNET_CRYPTO_eddsa_key_create (&private_key); + GNUNET_CRYPTO_eddsa_key_get_public (&private_key, + &public_key); + + /* Convert to crockford 32 and pring */ + char *priv_key; + char *pub_key; + priv_key = GNUNET_STRINGS_data_to_string_alloc (&private_key, + sizeof (private_key)); + pub_key = GNUNET_STRINGS_data_to_string_alloc (&public_key, + sizeof (public_key)); + + fprintf (stderr, "private signing key: %s\n", priv_key); + fprintf (stderr, "public signing key: %s\n", pub_key); + + + free (chall_method); + free (chall_data); + free (chall_context); + free (crock_id); + free (crock_key); + free (priv_key); + free (pub_key); + + struct FROST_HashState sig_id_state; + struct FROST_HashCode sig_id_hash; + FROST_hash_init (&sig_id_state); + + return 0; +} +\ No newline at end of file diff --git a/src/util/Makefile.am b/src/util/Makefile.am @@ -0,0 +1,41 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +pkgcfgdir = $(prefix)/share/frosix/config.d/ + + +EXTRA_DIST = \ + frosix-config.in \ + $(pkgcfg_DATA) + +edit_script = $(SED) -e 's,%libdir%,$(libdir),'g $(NULL) + +frosix-config: frosix-config.in + rm -f $@ $@.tmp && \ + $(edit_script) $< >$@.tmp && \ + chmod a-w+x $@.tmp && \ + mv $@.tmp $@ + +CLEANFILES = \ + frosix-config + +bin_SCRIPTS = \ + frosix-config + +lib_LTLIBRARIES = \ + libfrosixutil.la + +libfrosixutil_la_SOURCES = \ + os_installation.c \ + frosix_crypto.c \ + frosix-util.c \ + pin.c +libfrosixutil_la_LIBADD = \ + $(top_builddir)/src/libfrosthigh/libfrosthigh.la \ + -lgnunetutil \ + -ljansson \ + -ltalerutil \ + $(XLIB) +libfrosixutil_la_LDFLAGS = \ + -version-info 0:0:0 \ + -no-undefined diff --git a/src/util/frosix-config.c b/src/util/frosix-config.c @@ -0,0 +1,72 @@ +/* + This file is part of Frosix. + Copyright (C) 2012-2021 Anastasis Systems SA + + Frosix is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/** + * @file util/frosix-config.c + * @brief tool to access and manipulate Frosix configuration files + * @author Christian Grothoff + */ +#include "platform.h" +#include "frosix_util_lib.h" + + +/** + * Program to manipulate configuration files. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, + char *const *argv) +{ + struct GNUNET_CONFIGURATION_ConfigSettings cs = { + .api_version = GNUNET_UTIL_VERSION, + .global_ret = EXIT_SUCCESS + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + enum GNUNET_GenericReturnValue ret; + + if (GNUNET_OK != + GNUNET_STRINGS_get_utf8_args (argc, argv, + &argc, &argv)) + return EXIT_FAILURE; + FROSIX_OS_init (); + ret = GNUNET_PROGRAM_run (argc, + argv, + "frosix-config [OPTIONS]", + gettext_noop ( + "Manipulate Frosix configuration files"), + options, + &GNUNET_CONFIGURATION_config_tool_run, + &cs); + GNUNET_free_nz ((void *) argv); + GNUNET_CONFIGURATION_config_settings_free (&cs); + if (GNUNET_NO == ret) + return 0; + if (GNUNET_SYSERR == ret) + return EXIT_INVALIDARGUMENT; + return cs.global_ret; +} + + +/* end of frosix-config.c */ diff --git a/src/util/frosix-config.in b/src/util/frosix-config.in @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -eu + +if ! type gnunet-config >/dev/null; then + echo "$0 needs gnunet-config to be installed" + exit 1 +fi + +GC=`which gnunet-config` +export LD_PRELOAD=${LD_PRELOAD:-}:%libdir%/libfrosixutil.so +exec gnunet-config "$@" diff --git a/src/util/frosix-util.c b/src/util/frosix-util.c @@ -0,0 +1,60 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file util/frosix-util.c + * @brief helper functions for various tasks + * @author Joel Urech + */ + +#include "frosix_util_lib.h" +#include "frost_low.h" +#include "frost_high.h" + + + + + + +void +FROSIX_debug_print_point (const struct FROST_Point *pt) +{ + for (int i = 0; i < sizeof (pt); i++) + fprintf (stderr, "%02X ", pt->xcoord[i]); + fprintf (stderr, "\n"); +} + +void +FROSIX_debug_print_scalar (const struct FROST_Scalar *scal) +{ + for (int i = 0; i < sizeof (scal); i++) + fprintf (stderr, "%02X ", scal->scalarbytes[i]); + fprintf (stderr, "\n"); +} + +void +FROSIX_debug_print_crockford32 (const void *data, + size_t length, + const char *title) +{ + char *crock; + crock = GNUNET_STRINGS_data_to_string_alloc (data, + length); + fprintf (stderr, + "%s: %s\n", + title, + crock); + free (crock); +} diff --git a/src/util/frosix_crypto.c b/src/util/frosix_crypto.c @@ -0,0 +1,288 @@ +/* + This file is part of Frosix + Copyright (C) 2022, 2023 Joel Urech + + Frosix is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Frosix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file util/frosix_crypto.c + * @brief helper functions for various tasks + * @author Joel Urech + */ + +#include "frosix_crypto.h" +#include "frost_low.h" +#include "frost_high.h" + +enum GNUNET_GenericReturnValue +FROSIX_secretbox_keydata (struct FROSIX_KeyDataEncrypted *ciphertext, + const struct FROSIX_KeyDataRaw *plaintext, + const struct FROSIX_EncryptionNonceP *nonce, + const struct FROSIX_EncryptionKey *key) +{ + if (0 == crypto_secretbox_easy (ciphertext->bytes, + plaintext->bytes, + sizeof (plaintext->bytes), + nonce->bytes, + key->bytes)) + return GNUNET_OK; + return GNUNET_NO; +} + + +enum GNUNET_GenericReturnValue +FROSIX_secretbox_keydata_open (struct FROSIX_KeyDataRaw *plaintext, + const struct FROSIX_KeyDataEncrypted *ciphertext, + const struct FROSIX_EncryptionNonceP *nonce, + const struct FROSIX_EncryptionKey *key) +{ + if (0 == crypto_secretbox_open_easy (plaintext->bytes, + ciphertext->bytes, + sizeof (ciphertext->bytes), + nonce->bytes, + key->bytes)) + return GNUNET_OK; + return GNUNET_NO; +} + + +void +FROSIX_secretbox_nonce_randombytes (struct FROSIX_EncryptionNonceP *nonce) +{ + randombytes_buf (nonce, + sizeof (nonce->bytes)); +} + + +void +FROSIX_hash_encryption_key (struct FROST_HashCode *enc_key_hash, + const struct FROSIX_EncryptionKey *enc_key) +{ + struct FROST_HashState enc_key_state; + FROST_hash_init (&enc_key_state); + FROST_hash_fixed_update (&enc_key_state, + enc_key, + sizeof (*enc_key)); + FROST_hash_final (&enc_key_state, + enc_key_hash); +} + +void +FROSIX_compute_auth_hash (struct FROSIX_ChallengeHashP *auth_hash, + const char *auth_data, + const struct GNUNET_HashCode *auth_nonce) +{ + struct GNUNET_HashContext *h_ctx = GNUNET_CRYPTO_hash_context_start (); + GNUNET_CRYPTO_hash_context_read (h_ctx, + auth_data, + strlen (auth_data)); + GNUNET_CRYPTO_hash_context_read (h_ctx, + auth_nonce, + sizeof (*auth_nonce)); + GNUNET_CRYPTO_hash_context_read (h_ctx, + "FROSIX", + strlen ("FROSIX")); + GNUNET_CRYPTO_hash_context_finish (h_ctx, + &auth_hash->hash); +} + + +void +FROSIX_compute_challenge_request_id ( + struct FROSIX_ChallengeRequestIdP *request_id, + const struct FROSIX_EncryptionKey *enc_key, + const struct FROST_MessageHash *message_hash) +{ + /* id = H (encryption_key || + message_hash || + "FROSIX-SIG") */ + struct FROST_HashState hs; + + FROST_hash_init (&hs); + FROST_hash_fixed_update (&hs, + enc_key, + sizeof (*enc_key)); + FROST_hash_fixed_update (&hs, + message_hash, + sizeof (*message_hash)); + FROST_hash_fixed_update (&hs, + "FROSIX-AUTH", + strlen ("FROSIX-AUTH")); + FROST_hash_final (&hs, + &request_id->id); +} + + +void +FROSIX_compute_signature_request_id ( + struct FROSIX_SigRequestIdP *request_id, + const struct FROST_HashCode *enc_key_hash, + const struct FROST_MessageHash *message_hash) +{ + /* id = H (H(encryption_key) || + message_hash || + "FROSIX-SIG") */ + struct FROST_HashState hs; + + FROST_hash_init (&hs); + FROST_hash_fixed_update (&hs, + enc_key_hash, + sizeof (*enc_key_hash)); + FROST_hash_fixed_update (&hs, + message_hash, + sizeof (*message_hash)); + FROST_hash_fixed_update (&hs, + "FROSIX-SIG", + strlen ("FROSIX-SIG")); + FROST_hash_final (&hs, + &request_id->id); +} + +void +FROSIX_compute_dkg_request_id ( + struct FROSIX_DkgRequestIdP *request_id, + const struct FROSIX_DkgContextStringP *context_string, + const struct FROSIX_ChallengeHashP *challenge_hash, + const struct FROSIX_ProviderSaltP *provider_salt, + uint8_t provider_index, + uint8_t num_of_participants, + uint8_t threshold) +{ + struct FROST_HashState check_id_state; + + FROST_hash_init (&check_id_state); + FROST_hash_hash_update (&check_id_state, + &context_string->hash); + FROST_hash_fixed_update (&check_id_state, + &challenge_hash->hash, + sizeof (*challenge_hash)); + FROST_hash_uint8_update (&check_id_state, + provider_index); + FROST_hash_uint8_update (&check_id_state, + num_of_participants); + FROST_hash_uint8_update (&check_id_state, + threshold); + FROST_hash_fixed_update (&check_id_state, + provider_salt, + sizeof (*provider_salt)); + FROST_hash_fixed_update (&check_id_state, + "FROSIX-DKG-ID", + strlen ("FROSIX-DKG-ID")); + FROST_hash_final (&check_id_state, + &request_id->id); +} + + +enum GNUNET_GenericReturnValue +FROSIX_gnunet_hash_cmp (const struct GNUNET_HashCode *hc1, + const struct GNUNET_HashCode *hc2) +{ + if (0 == GNUNET_CRYPTO_hash_cmp (hc1, + hc2)) + return GNUNET_OK; + return GNUNET_NO; +} + +void +FROSIX_compute_challenge_id (struct FROSIX_ChallengeIdP *challenge_id, + const struct FROST_HashCode *enc_key_hash, + const struct FROST_MessageHash *mh) +{ + struct GNUNET_HashContext *hc = GNUNET_CRYPTO_hash_context_start (); + GNUNET_CRYPTO_hash_context_read (hc, + enc_key_hash, + sizeof (*enc_key_hash)); + GNUNET_CRYPTO_hash_context_read (hc, + mh, + sizeof (*mh)); + GNUNET_CRYPTO_hash_context_read (hc, + "FROSIX", + strlen ("FROSIX")); + GNUNET_CRYPTO_hash_context_finish (hc, + &challenge_id->hash); +} + +void +FROSIX_hash_answer (uint64_t code, + struct GNUNET_HashCode *hashed_code) +{ + char cbuf[40]; + + GNUNET_snprintf (cbuf, + sizeof (cbuf), + "%llu", + (unsigned long long) code); + GNUNET_CRYPTO_hash (cbuf, + strlen (cbuf), + hashed_code); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Hashed answer %llu to %s\n", + (unsigned long long) code, + GNUNET_h2s (hashed_code)); +} + + +void +FROSIX_nonce_to_pow_salt (struct FROST_PowSalt *salt, + const struct GNUNET_HashCode *nonce) +{ + GNUNET_CRYPTO_kdf (salt, + sizeof (*salt), + "FROSIX", + strlen ("FROSIX"), + nonce, + sizeof (*nonce), + NULL, + 0); +} + +void +FROSIX_hash_pow (struct GNUNET_HashCode *hash, + struct GNUNET_CRYPTO_Edx25519PrivateKey *priv, + struct GNUNET_CRYPTO_Edx25519PublicKey *pub, + const struct GNUNET_HashCode *nonce, + const char *auth_answer, + unsigned int amplifier) +{ + /* get salt */ + struct FROST_PowSalt salt; + FROSIX_nonce_to_pow_salt (&salt, + nonce); + + /* make big calculation*/ + struct FROST_HashCode hashed_answer; + FROST_pow_hash (&hashed_answer, + auth_answer, + strlen (auth_answer), + &salt, + amplifier); + + /* with the seed, get the private key */ + GNUNET_CRYPTO_edx25519_key_create_from_seed (&hashed_answer, + sizeof (hashed_answer), + priv); + + /* and the public key */ + GNUNET_CRYPTO_edx25519_key_get_public (priv, + pub); + + /* hash public key */ + struct GNUNET_HashContext *hc = GNUNET_CRYPTO_hash_context_start (); + GNUNET_CRYPTO_hash_context_read (hc, + pub, + sizeof (*pub)); + GNUNET_CRYPTO_hash_context_read (hc, + "FROSIX", + strlen ("FROSIX")); + GNUNET_CRYPTO_hash_context_finish (hc, + hash); +} +\ No newline at end of file diff --git a/src/util/os_installation.c b/src/util/os_installation.c @@ -0,0 +1,73 @@ +/* + This file is part of GNU Frosix. + Copyright (C) 2019, 2021 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + Frosix is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Frosix; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +/** + * @file os_installation.c + * @brief initialize libgnunet OS subsystem for Frosix. + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include "frost_high.h" + + +/** + * Default project data used for installation path detection + * for Frosix. + */ +static const struct GNUNET_OS_ProjectData frosix_pd = { + .libname = "libfrosixutil", + .project_dirname = "frosix", + .binary_name = "frosix-httpd", + .env_varname = "FROSIX_PREFIX", + .base_config_varname = "FROSIX_BASE_CONFIG", + .bug_email = "", + .homepage = "", + .config_file = "frosix.conf", + .user_config_file = "~/.config/frosix.conf", + .version = "0.0.0", + .is_gnu = 0, + .gettext_domain = "frosix", + .gettext_path = NULL, +}; + + +/** + * Return default project data used by Frosix. + */ +const struct GNUNET_OS_ProjectData * +FROSIX_project_data_default (void) +{ + return &frosix_pd; +} + + +/** + * Initialize libfrosixutil. + */ +void __attribute__ ((constructor)) +FROSIX_OS_init () +{ + GNUNET_OS_init (&frosix_pd); + GNUNET_assert (-1 != FROST_init ()); +} + + +/* end of os_installation.c */ diff --git a/src/util/pin.c b/src/util/pin.c @@ -0,0 +1,84 @@ +/* + This file is part of Frosix + Copyright (C) 2021 Anastasis SARL + + Frosix is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + Frosix is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Frosix; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +/** + * @file util/pin.c + * @brief pin conversion functions + * @author Christian Grothoff + */ +#include "platform.h" +#include "frosix_util_lib.h" + + +bool +FROSIX_scan_pin (const char *as, + unsigned long long *pin) +{ + char dummy; + char s[16]; + + if ( (NULL != as) && + (0 == strncasecmp ("A-", as, 2)) ) + as += 2; /* skip "A-" prefix if present */ + if (strlen (as) != 18) + return false; + if ( ('-' != as[5]) || + ('-' != as[9]) || + ('-' != as[14]) ) + return false; + GNUNET_snprintf (s, + sizeof (s), + "%.5s%.3s%.4s%.3s", + as, + &as[6], + &as[10], + &as[15]); + if (1 != sscanf (s, + "%llu%c", + pin, + &dummy)) + { + GNUNET_break (0); + return false; + } + return true; +} + + +const char * +FROSIX_pin2s (uint64_t pin) +{ + static char buf[22]; + char tmp[16]; + + GNUNET_assert (pin < FROSIX_PIN_MAX_VALUE); + GNUNET_snprintf (tmp, + sizeof (tmp), + "%015llu", + (unsigned long long) pin); + GNUNET_snprintf (buf, + sizeof (buf), + "A-%.5s-%.3s-%.4s-%.3s", + tmp, + &tmp[5], + &tmp[8], + &tmp[12]); + return buf; +}